bash/.local/share/blesh/lib/core-complete.sh
2024-08-18 03:40:38 +02:00

7520 lines
264 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Copyright 2015 Koichi Murase <myoga.murase@gmail.com>. All rights reserved.
# This script is a part of blesh (https://github.com/akinomyoga/ble.sh)
# provided under the BSD-3-Clause license. Do not edit this file because this
# is not the original source code: Various pre-processing has been applied.
# Also, the code comments and blank lines are stripped off in the installation
# process. Please find the corresponding source file(s) in the repository
# "akinomyoga/ble.sh".
#
# Source: /lib/core-complete.sh
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/string#match-patterns {
local s=$1 found= pattern; shift
for pattern; do
if [[ $s == $pattern ]]; then
return 0
fi
done
return 1
}
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_page_style=
_ble_complete_menu_page_index=
_ble_complete_menu_page_offset=
_ble_complete_menu_page_icons=()
_ble_complete_menu_page_infodata=()
_ble_complete_menu_selected=-1
function ble/complete/menu#check-cancel {
((menu_iloop++%menu_interval==0)) &&
[[ :$menu_construct_opts: != *:sync:* ]] &&
ble/decode/has-input
}
_ble_complete_menu_style_hash=
_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#get-prefix-width {
prefix_width=0
prefix_format=${1:-$bleopt_menu_prefix}
if [[ $prefix_format ]]; then
local prefix1 column_width=$2
ble/util/sprintf prefix1 "$prefix_format" "${#menu_items[@]}"
local x1 y1 x2 y2 g=0
LINES=1 COLUMNS=$column_width x=0 y=0 ble/canvas/trace "$prefix1" truncate:measure-bbox
if ((x2<=column_width/2)); then
prefix_width=$x2
ble/string#reserve-prototype "$prefix_width"
fi
fi
}
function ble/complete/menu#render-prefix {
prefix_esc=
local index=$1
if ((prefix_width)); then
local prefix1; ble/util/sprintf prefix1 "$prefix_format" "$((index+1))"
local x=0 y=0 g=0
LINES=1 COLUMNS=$prefix_width ble/canvas/trace "$prefix1" truncate:relative
prefix_esc=$ret$_ble_term_sgr0
if ((x<prefix_width)); then
prefix_esc=${_ble_string_prototype::prefix_width-x}$prefix_esc
fi
fi
}
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 prefix_esc
ble/complete/menu#render-prefix "$index"
local x=$prefix_width y=0
ble/complete/menu#render-item "$item"; esc1=$ret
local w=$((y*cols+x))
_ble_complete_menu_style_measure[index]=$w:${#item},${#esc1}:$item$esc1$prefix_esc
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 prefix_width prefix_format
ble/complete/menu#get-prefix-width "$bleopt_menu_align_prefix" "$bleopt_menu_align_max"
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 len; ble/string#split len , "$s"
local item=${entry::len[0]} esc1=${entry:len[0]:len[1]} prefix_esc=${entry:len[0]+len[1]}
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
((x+=prefix_width))
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+prefix_width)),$y0,$x,$y,${#item},${#esc1}:$item$esc1
esc=$esc$prefix_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 {
local prefix_width prefix_format
ble/complete/menu#get-prefix-width "$bleopt_menu_dense_prefix" "$cols"
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
local prefix_esc esc1
ble/complete/menu#render-prefix "$index"
((x+=prefix_width,x>cols&&(y+=x/cols,x%=cols)))
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,x0=0,x=prefix_width))
ble/complete/menu#render-item "$item" ||
((begin==index)) ||
{ x=$x0 y=$y0; break; }; esc1=$ret
fi
fi
local x1=$((x0+prefix_width)) y1=$y0
((x1>=cols)) && ((y1+=x1/cols,x1%=cols))
_ble_complete_menu_style_icons[index]=$x1,$y1,$x,$y,${#item},${#esc1}:$item$esc1
esc=$esc$prefix_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_width prefix_format
ble/complete/menu#get-prefix-width "$bleopt_menu_linewise_prefix" "$max_icon_width"
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
local prefix_esc=
ble/complete/menu#render-prefix "$index" "$max_icon_width"
esc=$esc$prefix_esc
((x=prefix_width))
((x0=x,y0=y))
local lines1=1 cols1=$max_icon_width
lines=$lines1 cols=$cols1 y=0 ble/complete/menu#render-item "$item"; esc1=$ret
_ble_complete_menu_style_icons[index]=$x0,$y0,$x,$y,${#item},${#esc1},"$x0 0 $cols1 $lines1":$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 menu_desc_quote; local desc_sgrq=$ret
ble/color/face2sgr-ansi menu_desc_type; 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 prefix_width prefix_format
ble/complete/menu#get-prefix-width "$bleopt_menu_desc_prefix" "$wcolumn"
((wcolumn>=prefix_width+15)) || prefix_width=0
local wcand_limit=$(((wcolumn-prefix_width+1)*2/3))
((wcand_limit<10&&(wcand_limit=wcolumn-prefix_width)))
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*wcand_limit+x,w>max_width&&(max_width=w)))
ble/array#push measure "$w:${#pack}:$pack$esc1"
done
local cand_width=$max_width
local desc_x=$((prefix_width+cand_width+1)); ((desc_x>wcolumn&&(desc_x=wcolumn)))
local desc_prefix=; ((wcolumn-prefix_width-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}
local prefix_esc
ble/complete/menu#render-prefix "$index"
ble/canvas/put.draw "$prefix_esc"
((x+=prefix_width))
((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:face0=menu_desc_default
else
ble/color/face2sgr menu_desc_default
ble/canvas/put.draw "$ret"
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_page_index
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_page_offset
local end=$((beg+${#_ble_complete_menu_page_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_construct_opts=$1
local menu_iloop=0
local menu_interval=$bleopt_complete_polling_cycle
_ble_complete_menu_items=("${menu_items[@]}")
_ble_complete_menu_class=$menu_class
_ble_complete_menu_param=$menu_param
_ble_complete_menu_selected=-1
local nitem=${#menu_items[@]}
if [[ :$menu_construct_opts: == *:hidden:* ]]; then
ble/array#reserve-prototype "$nitem"
_ble_complete_menu_page_style=
_ble_complete_menu_page_index=
_ble_complete_menu_page_offset=
_ble_complete_menu_page_icons=("${_ble_array_prototype[@]::nitem}")
_ble_complete_menu_page_infodata=(store 0 0 '')
return 0
elif ((nitem==0)); then
_ble_complete_menu_page_style=
_ble_complete_menu_page_index=0
_ble_complete_menu_page_offset=0
_ble_complete_menu_page_icons=()
_ble_complete_menu_page_infodata=(ansi $'\e[38;5;242m(no items)\e[m')
return 0
fi
local cols lines
ble/complete/menu#construct/.initialize-size
local hash=$nitem,$lines,$cols:$menu_style
local scroll=0 rex=':scroll=([0-9]+):' use_cache=
if [[ :$menu_construct_opts: =~ $rex ]]; then
scroll=${BASH_REMATCH[1]}
((nitem&&(scroll%=nitem)))
[[ $hash == "$_ble_complete_menu_style_hash" ]] && use_cache=1
fi
if [[ ! $use_cache ]]; then
_ble_complete_menu_style_measure=()
_ble_complete_menu_style_icons=()
_ble_complete_menu_style_pages=()
fi
_ble_complete_menu_style_hash=$hash
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_construct_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_page_style=$menu_style
_ble_complete_menu_page_index=$ipage
_ble_complete_menu_page_offset=$begin
_ble_complete_menu_page_icons=("${_ble_complete_menu_style_icons[@]:begin:end-begin}")
_ble_complete_menu_page_infodata=(store "$x" "$y" "$esc")
return 0
}
function ble/complete/menu#show {
ble/edit/info/immediate-show "${_ble_complete_menu_page_infodata[@]}"
}
function ble/complete/menu#clear {
ble/edit/info/default
}
function ble/complete/menu#select/.erase-item-selection.draw {
local i=$1
local entry=${_ble_complete_menu_page_icons[i]}
[[ $entry ]] || return 1
local fields text=${entry#*:}
ble/string#split fields , "${entry%%:*}"
((fields[3]<_ble_canvas_panel_height[_ble_edit_info_panel])) || return 1
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]))
}
function ble/complete/menu#select/.render-item-selection.draw {
local i=$1
local entry=${_ble_complete_menu_page_icons[i]}
[[ $entry ]] || return 1
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
((y<_ble_canvas_panel_height[_ble_edit_info_panel])) || return 12
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))
}
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=0
local visible_end=$ncand
if [[ :$_ble_complete_menu_opts: != *:hidden:* ]]; then
visible_beg=$_ble_complete_menu_page_offset
visible_end=$((visible_beg+${#_ble_complete_menu_page_icons[@]}))
if ((nsel>=0&&!(visible_beg<=nsel&&nsel<visible_end))); then
ble/complete/menu/show scroll="$nsel"; local ext=$?
((ext)) && return "$ext"
if [[ $_ble_complete_menu_page_index ]]; then
local ipage=$_ble_complete_menu_page_index
ble/term/visible-bell "menu: Page $((ipage+1))" persistent
else
ble/term/visible-bell "menu: Offset $_ble_complete_menu_page_offset/$ncand" persistent
fi
visible_beg=$_ble_complete_menu_page_offset
visible_end=$((visible_beg+${#_ble_complete_menu_page_icons[@]}))
((visible_end<=nsel&&(nsel=visible_end-1)))
((nsel<=visible_beg&&(nsel=visible_beg)))
((visible_beg<=osel&&osel<visible_end)) || osel=-1
fi
fi
local -a DRAW_BUFF=()
local ret; ble/canvas/panel/save-position; local pos0=$ret
if ((osel>=0)); then
ble/complete/menu#select/.erase-item-selection.draw "$((osel-visible_beg))"
fi
local value=
if ((nsel>=0)); then
[[ :$opts: == *:goto-page-top:* ]] && nsel=$visible_beg
ble/complete/menu#select/.render-item-selection.draw "$((nsel-visible_beg))"
_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_page_offset
local osel=$_ble_complete_menu_selected
((osel>=0)) || return 1
local entry=${_ble_complete_menu_page_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_page_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_page_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_page_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_page_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_page_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_page_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_page_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_page_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_page_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_page_offset>0)); then
ble/complete/menu#select "$((_ble_complete_menu_page_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_page_offset+${#_ble_complete_menu_page_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_page_offset"
}
function ble/widget/menu/end-of-page {
local nicon=${#_ble_complete_menu_page_icons[@]}
((nicon)) && ble/complete/menu#select "$((_ble_complete_menu_page_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
local i v
for ((i=1;i<${#comps_fixed[@]};i++)); do
v=${comps_fixed[i]#*:}
quote_fixed_compv[i]=$v
quote_fixed_compv_len[i]=${#v}
quote_fixed_comps_len[i]=${comps_fixed[i]%%:*}
quote_fixed_comps[i]=${COMPS::quote_fixed_comps_len[i]}
done
}
function ble/complete/action/quote-insert {
if [[ ! $quote_action ]]; then
local "${_ble_complete_quote_insert_varnames[@]/%/=}" # WA #D1570 checked
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 == *:ble/syntax-raw:* && $comp_opts != *:filenames:* ]] && 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
return 0
fi
local i=${#quote_fixed_comps[@]}
while ((--i>=0)); do
if [[ ${quote_fixed_comps[i]} && $CAND == "${quote_fixed_compv[i]}"* ]]; then
local ret; ble/complete/string#escape-for-completion-context "${CAND:quote_fixed_compv_len[i]}" "$escape_flags"
INSERT=${quote_fixed_comps[i]}$quote_trav_prefix$ret
return 0
fi
done
local ret; ble/complete/string#escape-for-completion-context "$CAND" "$escape_flags"
INSERT=$quote_trav_prefix$ret
}
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_count=${#quote_fixed_comps[@]}
local i
for ((i=0;i<quote_fixed_count;i++)); do
local -x "quote_fixed_comps$i=${quote_fixed_comps[i]}"
local -x "quote_fixed_compv$i=${quote_fixed_compv[i]}"
done
"$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, i) {
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:/;
is_syntaxraw = comp_opts ~ /:ble\/syntax-raw:/ && comp_opts !~ /:filenames:/;
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_count = ENVIRON["quote_fixed_count"];
for (i = 0; i < quote_fixed_count; i++) {
quote_fixed_comps[i] = ENVIRON["quote_fixed_comps" i];
quote_fixed_compv[i] = ENVIRON["quote_fixed_compv" i];
quote_fixed_comps_len[i] = length(quote_fixed_comps[i]);
quote_fixed_compv_len[i] = length(quote_fixed_compv[i]);
}
}
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, _, i) {
if (quote_action == "command") {
if (comps == compv && cand ~ /^(\[\[|]]|!)$/) return cand;
} else if (quote_action == "progcomp") {
if (is_noquote || is_syntaxraw) 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;
}
}
for (i = quote_fixed_count; --i >= 0; ) {
if (quote_fixed_comps_len[i] && substr(cand, 1, quote_fixed_compv_len[i]) == quote_fixed_compv[i]) {
ins = substr(cand, quote_fixed_compv_len[i] + 1);
return quote_fixed_comps[i] quote_trav_prefix escape_for_completion_context(ins);
}
}
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 <&"$_ble_util_fd_tui_stdin"' '' 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 threshold=$((bleopt_complete_requote_threshold))
((threshold>=0)) || return 0
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/safe-eval "$ins" &&
((${#ret[@]}==1))
then
ble/string#quote-word "$ret" quote-empty
((${#ret}+threshold<=${#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 init-menu-item; 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 { return 0; }
function ble/complete/action:literal-substr/initialize.batch { inserts=("${cands[@]}"); }
function ble/complete/action:literal-substr/complete { return 0; }
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 { return 0; }
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/.get-filename {
ret=$CAND
if [[ $ACTION == progcomp && :$DATA: == *:ble/syntax-raw:* && $ret == '~'* ]]; then
local tilde=${ret%%/*} chars='\ "'\''`$|&;<>()!^*?[=:{,}'
[[ $tilde == *["$chars"]* ]] && return 0
builtin eval "local expand=$tilde"
[[ $expand == "$tilde" ]] && return 0
ret=$expand${ret:${#tilde}}
fi
}
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 {
local ret
ble/complete/action:file/.get-filename
if [[ -e $ret || -h $ret ]]; then
if [[ -d $ret ]]; then
ble/complete/action/requote-final-insert
ble/complete/action/complete.mark-directory
else
ble/complete/action:word/complete
fi
else
ble/complete/action:word/complete
fi
}
function ble/complete/action:file/init-menu-item {
local ret
ble/complete/action:file/.get-filename; local file=$ret
ble/syntax/highlight/getg-from-filename "$file"
[[ $g ]] || { local ret; ble/color/face2g filename_warning; g=$ret; }
if [[ :$comp_type: == *:vstat:* ]]; then
if [[ -h $file ]]; then
suffix='@'
elif [[ -d $file ]]; then
suffix='/'
elif [[ -x $file ]]; 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 ! ble/bin#has "$CAND"; 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/bin#get-path "$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 checked
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 checked
ble/complete/cand/yield.initialize "$action"
for cand; do
[[ $cand == "$COMPV"* ]] && ble/complete/cand/yield "$action" "$cand"
done
}
function ble/complete/action:suffix-sabbrev/initialize {
ble/complete/action/quote-insert
}
function ble/complete/action:suffix-sabbrev/initialize.batch {
ble/complete/action/quote-insert.batch newline
}
function ble/complete/action:suffix-sabbrev/complete {
ble/complete/action/requote-final-insert
ble/complete/action/complete.close-quotation
}
function ble/complete/action:suffix-sabbrev/init-menu-item {
local ret; ble/color/face2g command_suffix; g=$ret
}
function ble/complete/action:suffix-sabbrev/get-desc {
local key1= ent1=
if [[ $CAND == *.* ]] && ble/complete/sabbrev#match "$CAND" 's'; then
local ret
ble/string#quote-word "${ent1#*:}" sgrq="$desc_sgrq":sgr0="$desc_sgr0"
desc="$desc_sgrt(suffix)$desc_sgr0 .$key1=$ret"
else
desc="$desc_sgrt(suffix)$desc_sgr0 ??? (unmatching)"
fi
}
function ble/complete/source:command/.is-suffix-sabbrev {
[[ $1 =~ $source_file_regex ]] &&
! ble/complete/sabbrev/suffix.is-normal-command "$1"
}
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 {
if [[ $COMPV == */* && :$comp_type: == *:[maA]:* ]]; 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
ble/array#filter ret '[[ ! -d $1 && -x $1 ]]'
((${#ret[@]})) && printf '%s\n' "${ret[@]}"
local COMPS=$COMPS COMPV=$COMPV
ble/complete/source/reduce-compv-for-ambiguous-match
else
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
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 checked
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 ]] && ! ble/bin#has "$cand" && 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" && ! ble/bin#has "$cand" && 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"
local ret
if ble/complete/sabbrev/suffix.construct-regex; then
local source_file_regex=$ret
local source_file_filter=ble/complete/source:command/.is-suffix-sabbrev
ble/complete/source:file filter:action=suffix-sabbrev
fi
}
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 <&"$_ble_util_fd_tui_stdin"; then
ble/util/invoke-hook dtor
return 148
fi
builtin eval -- "$def"
fi
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 == .. || $name == . && i -lt ${#names[@]} ]]; then
pattern=$pattern$name
elif [[ $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 {
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]+-?$|^-$'
[[ :$opts: == *:filter-by-regex:* ]] &&
ble/array#filter-by-regex candidates "$source_file_regex"
[[ :$opts: == *:filter:* ]] &&
ble/array#filter candidates "$source_file_filter"
local action=file ret=
ble/opts#extract-last-optarg "$opts" action
[[ $ret ]] && action=$ret
local flag_source_filter=1
ble/complete/cand/yield-filenames "$action" "${candidates[@]}"
}
function ble/complete/source:dir {
ble/complete/source:file "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 {
[[ $comp_filter_type == none ]] &&
local comp_filter_type=head
local old_cand_count=$cand_count
local action=word "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 checked
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
ble/fd#is-cloexit "$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" "$wordbreaks"
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" "$wordbreaks"
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
}
builtin unset -v _ble_complete_progcomp_cur_wordbreaks
_ble_complete_progcomp_cur_rex_simple=
_ble_complete_progcomp_cur_rex_break=
function ble/complete/progcomp/.compvar-reduce-cur {
if [[ ! ${_ble_complete_progcomp_cur_wordbreaks+set} || $COMP_WORDBREAKS != "$_ble_complete_progcomp_cur_wordbreaks" ]]; then
_ble_complete_progcomp_cur_wordbreaks=$COMP_WORDBREAKS
_ble_complete_progcomp_cur_rex_simple='^([^\"'\'']|\\.|"([^\"]|\\.)*"|'\''[^'\'']*'\'')*'
local chars=${COMP_WORDBREAKS//[\'\"]/} rex_break=
[[ $chars == *\\* ]] && chars=${chars//\\/} rex_break='\\(.|$)'
[[ $chars == *\$* ]] && chars=${chars//\$/} rex_break+=${rex_break:+'|'}'\$([^$'\'${rex_break:+\\}']|$)'
if [[ $chars == '^' ]]; then
rex_break+=${rex_break:+'|'}'\^'
elif [[ $chars ]]; then
[[ $chars == ?*']'* ]] && chars=']'${chars//']'/}
[[ $chars == '^'* ]] && chars=${chars:1}${chars::1}
[[ $chars == *'-'*? ]] && chars=${chars//'-'/}'-'
rex_break+=${rex_break:+'|'}[$chars]
fi
_ble_complete_progcomp_cur_rex_break='^([^\"'\''$]|\$*\\.|\$*"([^\"]|\\.)*"|'\''[^'\'']*'\''|\$+'\''([^'\''\]|\\.)*'\''|\$+([^'\'']|$))*\$*('${rex_break:-'^$'}')'
fi
cur=$1
if [[ $cur =~ $_ble_complete_progcomp_cur_rex_simple && ${cur:${#BASH_REMATCH}} == [\'\"]* ]]; then
cur=${cur:${#BASH_REMATCH}+1}
elif [[ $cur =~ $_ble_complete_progcomp_cur_rex_break ]]; then
cur=${cur:${#BASH_REMATCH}}
case ${BASH_REMATCH[5]} in (\$*|@|\\?) cur=${BASH_REMATCH[5]#\\}$cur ;; esac
fi
}
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=()
cmd=${comp_words[0]}
cur= prev=
local ret simple_flags simple_ibrace
local word1 index=0 offset=0 sep=
for word1 in "${comp_words[@]}"; do
local offset_dst=${#COMP_LINE}
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))
ble/complete/progcomp/.compvar-reduce-cur "${COMP_LINE:offset_dst}${wq::p}"
prev=${COMP_WORDS[COMP_CWORD-1]}
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 cmd cur prev
local -x COMP_LINE COMP_POINT COMP_TYPE COMP_KEY
ble/complete/progcomp/.compvar-initialize
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/.error {
if ((_ble_bash>=40000&&$#>=2)); then
builtin compopt "${@:2}"
else
ble/util/print "ble.sh: compopt: $1" >&2
fi
has_error=1
}
function ble/complete/progcomp/compopt/.enable {
if [[ $1 == ble/no-default ]]; then
ble/complete/progcomp/compopt/.disable ble/default
return "$?"
elif [[ ! $1 || $1 == *:* ]]; then
ble/complete/progcomp/compopt/.error "$1: invalid option name" -o "$1"
return "$?"
fi
ble/array#push ospec "-$1"
ble/array#push compopt_args -o "$1"
}
function ble/complete/progcomp/compopt/.disable {
if [[ $1 == ble/no-default ]]; then
ble/complete/progcomp/compopt/.enable ble/default
return "$?"
elif [[ ! $1 || $1 == *:* ]]; then
ble/complete/progcomp/compopt/.error "$1: invalid option name" +o "$1"
return "$?"
fi
ble/array#push ospec "+$1"
ble/array#push compopt_args +o "$1"
}
function ble/complete/progcomp/compopt/.read-arguments {
ospec=() has_cmd= compopt_args=()
local has_error= has_stop= has_help=
while (($#)); do
local arg=$1; shift
if [[ $arg == [-+]?* && ! $has_stop ]]; then
case $arg in
(--?*)
case $arg in
(--help) has_help=1 ;;
(*)
ble/complete/progcomp/compopt/.error "unrecognized long option '$arg'" ;;
esac ;;
(--) has_stop=1 ;;
(-*)
arg=${arg:1}
while [[ $arg ]]; do
local c=${arg::1}
arg=${arg:1}
case $c in
(o)
if [[ ! $arg ]]; then
if (($#)); then
arg=$1; shift
else
ble/complete/progcomp/compopt/.error '-o: option requires an argument' -o
break 2
fi
fi
ble/complete/progcomp/compopt/.enable "$arg"
arg= ;;
([DEI])
ble/array#push compopt_args "-$c"
has_cmd=1 ;;
(*)
ble/complete/progcomp/compopt/.error "-$c: invalid option" "-$c" ;;
esac
done ;;
(+o)
arg=${arg:2}
if [[ ! $arg ]]; then
if (($#)); then
arg=$1; shift
else
ble/complete/progcomp/compopt/.error '+o: option requires an argument' +o
break
fi
fi
ble/complete/progcomp/compopt/.disable "$arg" ;;
(*)
ble/complete/progcomp/compopt/.error "$arg: invalid option" "$arg" ;;
esac
else
ble/array#push compopt_args "$arg"
has_cmd=1
has_stop=1 # Bash's compopt stops parsing options on any name
fi
done
if [[ $has_error ]]; then
return 2
elif [[ $has_help ]]; then
if ((_ble_bash>=40000)); then
builtin help compopt
else
ble/util/print-lines \
'compopt: compopt [-o|+o option] [-DEI] [name ...]' \
' Modify or display completion options.' '' >&2
fi
return 2
fi
return 0
}
function ble/complete/progcomp/compopt {
local ospec has_cmd compopt_args
ble/complete/progcomp/compopt/.read-arguments "$@" || return 2
if ((${#ospec[@]})); then
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
elif [[ $has_cmd ]]; then
builtin compopt "${compopt_args[@]}"
else
local option options out='compopt'
ble/string#split options : "${comp_opts%:}"
"${_ble_util_set_declare[@]//NAME/mark}" # WA #D1570 checked
ble/set#add mark ''
for option in "${options[@]}"; do
ble/set#contains mark "$option" && continue
ble/set#add mark "$option"
out="$out -o $option"
done
ble/util/print "$out"
fi
}
function ble/complete/progcomp/.check-limits {
((cand_iloop++%bleopt_complete_polling_cycle==0)) &&
[[ ! -t 0 ]] && ble/complete/check-cancel <&"$_ble_util_fd_tui_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 cmd cur prev
ble/complete/progcomp/.compvar-initialize
local progcomp_read_count=0
local _ble_builtin_read_hook='ble/complete/progcomp/.check-limits || { ble/bash/read "$@" < /dev/null; return 148; }'
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_tui_stdin" 128 progressive-weight:killall
else
ble/function#push/call-top "$@"
fi'
ble/function#push command_not_found_handle
builtin eval '"$comp_func" "$cmd" "$cur" "$prev"' < /dev/null >&"$_ble_util_fd_tui_stdout" 2>&"$_ble_util_fd_tui_stderr"; local ret=$?
ble/function#pop command_not_found_handle
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%' '}
((_ble_bash>=50200)) && builtin eval "comp_func=($comp_func)"
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 [[ $comp_cword -gt 0 && $COMPV != [!-]* ]]; then
local cmd=$compcmd
if [[ $cmd == _DefaultCmD_ || $cmd == _InitialWorD_ || $cmd == -[DI] ]]; then
cmd=${comp_words[0]}
local ret
ble/syntax:bash/simple-word/safe-eval "$cmd" nonull && cmd=$ret
fi
local man_page=${cmd##*/}
if [[ $man_page == git ]]; then
local isubcmd
for ((isubcmd=1;isubcmd<comp_cword;isubcmd++)); do
local subcmd=${comp_words[isubcmd]} ret
if ble/syntax:bash/simple-word/safe-eval "$subcmd"; then
((${#ret[@]})) || continue
subcmd=$ret
fi
if [[ $subcmd != -* ]]; then
man_page=git-$subcmd
break
fi
done
fi
if local ret; ble/complete/mandb/generate-cache "$man_page" "bin=$command"; then
require_awk=1
args_mandb=(mode=mandb "$ret")
fi
fi
if [[ $require_awk ]]; then
local fs=$_ble_term_FS
local awk_script='
BEGIN { mandb_count = 0; }
mode == "mandb" {
name = $0
sub(/'"$_ble_term_FS"'.*/, "", name);
if (!mandb[name]) mandb[name] = $0;
next;
}
function register_mandb_entry(name, display, entry) {
if (display ~ /(=)$/ && match(entry, /^[^'$fs']*'$fs'[^'$fs']*'$fs' '$fs'/) > 0)
entry = substr(entry, 1, RLENGTH - 2) "=" substr(entry, RLENGTH);
if (name2index[name] != "") {
if (length(display) <= length(name2display[name])) return;
name2display[name] = display;
entries[name2index[name]] = entry;
} else {
name2index[name] = mandb_count;
name2display[name] = display;
entries[mandb_count++] = entry;
}
}
!hash[$0]++ {
if (/^$/) next;
name = $0
sub(/(=)$/, "", name);
if (mandb[name]) {
register_mandb_entry(name, $0, 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, /['"$_ble_term_space"']*[:=[]/)) {
option = substr($0, 1, RSTART - 1);
optarg = substr($0, RSTART);
suffix = substr($0, RSTART, 1);
if (suffix == "[") suffix = "";
} else {
option = $0;
optarg = "";
suffix = " ";
}
register_mandb_entry(name, $0, option FS optarg FS suffix FS desc);
}
next;
}
}
print $0;
}
END {
if (mandb_count) {
for (i = 0; i < mandb_count; i++)
print entries[i];
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/patch:bash-completion/_comp_cmd_make.advice {
if [[ ${BLE_ATTACHED-} ]]; then
ble/function#push "${ADVICE_WORDS[1]}" '
local -a make_args; make_args=("${ADVICE_WORDS[1]}" "$@")
ble/util/conditional-sync \
'\''command "${make_args[@]}"'\'' \
"! ble/complete/check-cancel <&$_ble_util_fd_tui_stdin" 128 progressive-weight:killall'
ble/function#advice/do
ble/function#pop "${ADVICE_WORDS[1]}"
else
ble/function#advice/do
fi
}
function ble/complete/progcomp/patch:cobraV2/extract_activeHelp.patch {
local cobra_version=$1
if ((cobra_version<10500)); then
local -a completions
completions=("${out[@]}")
fi
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
elif [[ $line ]]; then
ble/array#push unprocessed "$line"
fi
done
done
[[ $has_desc ]] && bleopt complete_menu_style=desc
if ((${#unprocessed[@]})); then
if ((cobra_version>=10500)); then
completions=("${unprocessed[@]}")
else
out=("${unprocessed[@]}")
fi
ble/function#advice/do
fi
}
function ble/complete/progcomp/patch:cobraV2/get_completion_results.advice {
local -a orig_words
orig_words=("${words[@]}")
local -a words
words=(ble/complete/progcomp/patch:cobraV2/get_completion_results.invoke "${orig_words[@]:1}")
ble/function#advice/do
}
function ble/complete/progcomp/patch:cobraV2/get_completion_results.invoke {
local -a invoke_args; invoke_args=("$@")
ble/util/conditional-sync \
"${orig_words[0]} \"\${invoke_args[@]}\"" \
"! ble/complete/check-cancel <&$_ble_util_fd_tui_stdin" 128 progressive-weight:killall
}
function ble/complete/progcomp/call-by-conditional-sync {
ble/is-function "$1" || return 0
ble/function#advice around "$1" '
ble/util/conditional-sync \
ble/function#advice/do \
"! ble/complete/check-cancel <&$_ble_util_fd_tui_stdin" 128 progressive-weight:killall'
}
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=${cmd:-${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"
local comp_opts_parsed=$comp_opts
if [[ $comp_func ]]; then
[[ $comp_func == _fzf_* ]] &&
ble-import -f contrib/integration/fzf-completion
if ble/is-function _comp_initialize; then
ble/complete/mandb:bash-completion/inject
elif 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/function#suppress-stderr _function 2>/dev/null
ble/complete/mandb:bash-completion/inject
fi
if [[ $comp_func == _make || $comp_func == _comp_cmd_make ]] && ble/is-function "$comp_func"; then
ble/function#advice around "$comp_func" ble/complete/progcomp/patch:bash-completion/_comp_cmd_make.advice
fi
if [[ $comp_func == __start_* ]]; then
local target=__${comp_func#__start_}_handle_completion_types
if ble/is-function "$target"; then
local cobra_version=
if ble/is-function "__${comp_func#__start_}_extract_activeHelp"; then
cobra_version=10500 # v1.5.0 (Release 2022-06-21)
fi
ble/function#advice around "$target" "ble/complete/progcomp/patch:cobraV2/extract_activeHelp.patch $cobra_version"
fi
local target=__${comp_func#__start_}_get_completion_results
if ble/is-function "$target"; then
ble/function#advice around "$target" ble/complete/progcomp/patch:cobraV2/get_completion_results.advice
fi
fi
[[ $comp_func == _dnf ]] &&
ble/complete/progcomp/call-by-conditional-sync _dnf_commands_helper
if [[ $comp_func == _z || $comp_func == __zoxide_z_complete ]]; then
ble-import -f contrib/integration/zoxide
ble/contrib/integration:zoxide/adjust
fi
if [[ $comp_func == _complete_nix ]]; then
ble-import -f integration/nix-completion
ble/contrib/integration:nix-completion/adjust
fi
ble/function#suppress-stderr _adb 2>/dev/null
[[ $comp_func == _docker ]] &&
ble/complete/progcomp/call-by-conditional-sync __docker_q
[[ $comp_func == _docker_compose ]] &&
ble/complete/progcomp/call-by-conditional-sync __docker_compose_q
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
if [[ $comp_opts_parsed != *:plusdirs:* && $comp_opts == *:plusdirs:* ]]; then
local compgen_plusdirs=
ble/util/assign compgen_plusdirs 'builtin compgen -o plusdirs -- "$compgen_compv" 2>/dev/null'
[[ $compgen_plusdirs ]] && compgen=$compgen$'\n'$compgen_plusdirs
fi
[[ $compgen ]] || return 1
local use_workaround_for_git=
if [[ $comp_func == __git* && $comp_opts == *:nospace:* ]]; then
use_workaround_for_git=1
ble/string#match "$compgen" $'(^|\n|[^[:space:]])(\n|$)' ||
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
if [[ $comp_opts == *:filenames:* ]]; then
if [[ $comp_opts == *:ble/syntax-raw:* ]]; then
[[ $COMPS == */* ]] && COMP_PREFIX=${COMPS%/*}/
else
[[ $COMPV == */* ]] && COMP_PREFIX=${COMPV%/*}/
fi
fi
local old_cand_count=$cand_count
local action=progcomp "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 checked
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 checked
else
cands=("${cands[@]/#/$progcomp_prefix}") # WA #D1570 #D1738 checked
fi
fi
ble/complete/cand/yield.batch "$action" "$comp_opts"
((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-Z0-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/.try-load-completion {
if ble/is-function _comp_load; then
ble/function#push command_not_found_handle
_comp_load -- "$1" < /dev/null &>/dev/null; local ext=$?
ble/function#pop command_not_found_handle
elif ble/is-function __load_completion; then
ble/function#push command_not_found_handle
__load_completion "$1" < /dev/null &>/dev/null; local ext=$?
ble/function#pop command_not_found_handle
else
return 1
fi
((ext==0)) || return "$ext"
builtin complete -p -- "$1" &>/dev/null
}
function ble/complete/progcomp {
local cmd=${1-${comp_words[0]}} opts=$2
local orig_comp_words orig_comp_cword=$comp_cword orig_comp_line=$comp_line orig_comp_point=$comp_point
orig_comp_words=("${comp_words[@]}")
local comp_words comp_cword=$comp_cword comp_line=$comp_line comp_point=$comp_point
comp_words=("${orig_comp_words[@]}")
[[ $cmd == "${orig_comp_words[0]}" ]] ||
ble/complete/progcomp/.compline-rewrite-command "$cmd"
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
cmd=$ucmd
ble/complete/progcomp/.compline-rewrite-command "${qcmds[@]}" "${alias_args[@]}"
ble/complete/progcomp/.compgen "$opts"
return "$?"
elif [[ $ucmd == */?* ]] && builtin complete -p -- "${ucmd##*/}" &>/dev/null; then
cmd=${ucmd##*/}
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/complete/progcomp/.try-load-completion "${ucmd##*/}"; then
cmd=${ucmd##*/}
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[@]}")
comp_cword=$orig_comp_cword
comp_line=$orig_comp_line
comp_point=$orig_comp_point
[[ $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 ble/bash/read 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 0
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/nroff -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 LC_ALL= LC_COLLATE=C 2>/dev/null
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 all_flush(_, i) {
stage_flush();
fmt3_flush();
fmt5_flush();
fmt6_flush();
}
function all_reset() {
g_keys_count = 0;
g_desc = "";
mode = "none";
prev_line = "";
fmt3_state = "";
fmt5_state = "";
fmt6_state = "";
}
mode == "begin" && /^\.(Dd|Nm)['"$_ble_term_space"']/ {
if (type == "man" && /^\.Dd['"$_ble_term_space"']+\$Mdoc/) topic_start = "";
print $0;
}
function stage_key(key) {
g_keys[g_keys_count++] = key;
g_desc = "";
}
function stage_desc(desc) {
if (g_desc != "") g_desc = g_desc "\n";
g_desc = g_desc desc;
}
function stage_flush() {
if (g_keys_count == 0) return;
for (i = 0; i < g_keys_count; i++)
output_pair(g_keys[i], g_desc);
g_keys_count = 0;
g_desc = "";
mode = "none";
}
/^\.ig/ { mode = "ignore"; next; }
mode == "ignore" {
if (/^\.\.['"$_ble_term_space"']*/) mode = "none";
next;
}
{
sub(/['"$_ble_term_space"']+$/, "");
REQ = match($0, /^\.[_a-zA-Z0-9]+/) ? substr($0, 2, RLENGTH - 1) : "";
}
REQ ~ /^(S[Ss]|S[Hh]|Pp)$/ { all_flush(); next; }
function fmt7_check_start() {
if (prev_line == "") return 0;
if (g_keys_count || mode !~ /^(begin|none)$/) return 0;
if (fmt3_state != "") return 0;
if (fmt5_state !~ /^$|^key$/) return 0;
if (fmt6_state != "") return 0;
fmt5_state = "desc";
fmt5_key = prev_line;
fmt5_desc = "";
return 1;
}
REQ == "RS" && fmt7_check_start() { next; }
REQ == "PP" {
all_flush();
fmt5_state = "key";
fmt5_key = "";
fmt5_desc = "";
next;
}
fmt5_state {
if (fmt5_state == "key") {
if (/^\.RS([^_a-zA-Z0-9]|$)/)
fmt5_state = "desc";
else if (/^\.RE([^_a-zA-Z0-9]|$)/)
fmt5_state = "";
else
fmt5_key = (fmt5_key ? fmt5_key "\n" : "") $0;
} else if (fmt5_state == "desc") {
if (/^\.RE([^_a-zA-Z0-9]|$)/) {
fmt5_flush();
all_reset();
} else {
fmt5_desc = (fmt5_desc ? fmt5_desc "\n" : "") $0;
}
}
}
function fmt5_flush() {
if (fmt5_state == "desc") {
stage_key(fmt5_key);
stage_desc(fmt5_desc);
stage_flush();
}
fmt5_state = "";
}
REQ == "HP" {
all_flush();
fmt3_state = "key";
fmt3_key_count = 0;
fmt3_desc = "";
next;
}
function fmt3_process(_, key) {
if (REQ == "TP") { fmt3_switch(); return; }
if (REQ == "PD") return;
if (fmt3_state == "key") {
if (REQ == "IP") { fmt3_state = "desc"; return; }
if (match($0, /( | )['"$_ble_term_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_switch(_, i) {
if (fmt3_state == "desc" && fmt3_key_count > 0) {
for (i = 0; i < fmt3_key_count; i++)
stage_key(fmt3_keys[i]);
stage_desc(fmt3_desc);
mode = "desc"; # switch to normal "desc" processing
}
fmt3_state = "";
fmt3_key_count = 0;
fmt3_desc = "";
}
function fmt3_flush() {
fmt3_switch();
stage_flush();
}
fmt3_state { fmt3_process(); }
/^\.IP['"$_ble_term_space"']+".*"(['"$_ble_term_space"']+[0-9]+)?$/ && fmt3_state != "key" {
fmt6_init();
fmt4_init();
next;
}
function fmt4_init() {
if (mode != "fmt4_desc")
if (!(g_keys_count && g_desc == "")) all_flush();
gsub(/^\.IP['"$_ble_term_space"']+"|"(['"$_ble_term_space"']+[0-9]+)?$/, "");
stage_key($0);
mode = "fmt4_desc";
}
mode == "fmt4_desc" {
if ($0 == "") { all_flush(); 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['"$_ble_term_space"']+Item['"$_ble_term_space"']+/) next;
stage_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([^_a-zA-Z0-9]|$)/ {
if (g_keys_count && g_desc != "") all_flush();
sub(/^\.It Fl/, ".Fl");
if ($0 ~ / Xo$/) {
g_current_key = $0;
mode = "fmt2_keyc"
} else {
stage_key($0);
mode = "desc";
}
next;
}
mode == "fmt2_keyc" {
if (/^\.PD['"$_ble_term_space"']*([0-9]+['"$_ble_term_space"']*)?$/) next;
g_current_key = g_current_key "\n" $0;
if (REQ == "Xc") {
stage_key(g_current_key);
mode = "desc";
}
next;
}
type == "man" && REQ == "TP" {
if (g_keys_count && g_desc != "") all_flush();
mode = "key1";
next;
}
function fmt1_process_key(line, _, key, desc) {
if (match(line, /['"$_ble_term_space"']['"$_ble_term_space"']['"$_ble_term_space"']/) > 0) {
key = substr(line, 1, RSTART - 1)
desc = substr(line, RSTART);
sub(/^['"$_ble_term_space"']+/, "", desc);
stage_key(key);
stage_desc(desc);
} else {
stage_key(line);
}
mode = "desc";
}
mode == "key1" {
if (/^\.PD['"$_ble_term_space"']*([0-9]+['"$_ble_term_space"']*)?$/) next;
fmt1_process_key($0);
next;
}
mode == "desc" {
if (REQ == "PD") next;
stage_desc($0);
next;
}
{ prev_line = $0; }
END { all_flush(); }
' | ble/complete/mandb/convert-mandoc 2>/dev/null | ble/bin/awk -F "$_ble_term_FS" '
function flush_pair(_, i, desc, prev_opt) {
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++) {
desc = g_desc;
if (i > 0 && g_options[i] ~ /^--/) {
prev_opt = g_options[i - 1];
sub(/\034.*/, "", prev_opt);
if (prev_opt ~ /^-[^-]$/)
desc = "\033[1m[\033[0;36m" prev_opt "\033[0;1m]\033[m " desc;
}
print g_options[i] FS desc;
}
}
g_option_count = 0;
g_desc = "";
}
function process_key(line, _, n, specs, i, spec, option, optarg, suffix) {
gsub(/^['"$_ble_term_space"']+|['"$_ble_term_space"']+$/, "", line);
if (line == "") return;
gsub(/\x1b\[[ -?]*[@-~]/, "", line); # CSI seq
gsub(/\x1b[ -\/]*[0-~]/, "", line); # ESC seq
gsub(/\t/, " ", line); # HT
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(/^['"$_ble_term_space"']*|['"$_ble_term_space"']*$/, "", line);
gsub(/['"$_ble_term_space"']+/, " ", line);
if (line !~ /^[-+]./) return;
n = split(line, specs, /,(['"$_ble_term_space"']+|$)| or /);
prev_optarg = "";
for (i = n; i > 0; i--) {
spec = specs[i];
sub(/,['"$_ble_term_space"']+$/, "", spec);
if (spec !~ /^[-+]/ || spec ~ /\034/) { specs[i] = ""; continue; }
if (match(spec, /\[[:=]?|[:='"$_ble_term_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(/^[^'"$_ble_term_space"'[]/, " &", optarg);
} else {
if (optarg ~ /^\[[^:=]/)
sub(/^\[/, "[=", optarg);
else if (optarg ~ /^[^:='"$_ble_term_space"'[]/)
optarg = " " optarg;
}
if (match(optarg, /^\[[:=]?|^[:='"$_ble_term_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(/^['"$_ble_term_space"']*|['"$_ble_term_space"']*$/, "", line);
if (line == "") {
if (g_desc != "") return 0;
return 1;
}
gsub(/['"$_ble_term_space"']['"$_ble_term_space"']+/, " ", line);
if (g_desc != "") g_desc = g_desc " ";
g_desc = g_desc line;
return 1;
}
function process_string_fragment(str) {
if (mode == "key") {
process_key(str);
} else if (mode == "desc") {
if (!process_desc(str)) mode = "";
}
}
function process_line(line, _, head, m0) {
gsub(/||||﹣/, "-", line);
while (match(line, /__ble_(key|desc)__/) > 0) {
head = substr(line, 1, RSTART - 1);
m0 = substr(line, RSTART, RLENGTH);
line = substr(line, RSTART + RLENGTH);
process_string_fragment(head);
if (m0 == "__ble_key__") {
flush_pair();
mode = "key";
} else {
mode = "desc";
}
}
process_string_fragment(line);
}
{ process_line($0); }
END { flush_pair(); }
' | ble/bin/sort -t "$_ble_term_FS" -k 1
ble/util/unlocal LC_COLLATE LC_ALL 2>/dev/null
}
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'(<[^<>]+>|\([^()]+\)|\[[^][]+\]|[^-'"$_ble_term_space"'、。][^'"$_ble_term_space"'、。]*))?([,'"$_ble_term_space"']|$)'
local LC_ALL= LC_COLLATE=C 2>/dev/null
ble/bin/awk -F "$_ble_term_FS" '
BEGIN {
cfg_help = ENVIRON["cfg_help"];
g_help_indent = -1;
g_help_score = -1; # score based on indent and the interval between the
g_help_keys_count = 0;
g_help_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;
entries_init();
}
function entries_init() {
entries_count = 0;
}
function entries_register(entry, score, _, name, ientry) {
name = entry;
sub(/'"$_ble_term_FS"'.*$/, "", name);
if (name ~ /^\+/ && !cfg_plus) return;
if (entries_index[name] != "") {
if (score >= entries_score[name]) return;
ientry = entries_index[name];
} else {
ientry = entries_count++;
entries_keys[ientry] = name;
}
entries_index[name] = ientry;
entries_entry[name] = entry;
entries_score[name] = score;
}
function entries_dump(_, ientry, name) {
for (ientry = 0; ientry < entries_count; ientry++) {
name = entries_keys[ientry];
print entries_entry[name];
}
}
function str_convert_bs2ansi(str, _, head, n, a, c, flag_bold, flag_underline, i, prefix, suffix) {
if (str !~ /\x08/) return str;
print "str = " str >> "./a.txt"
head = "";
while (match(str, /(.\x08)+./) > 0) {
n = split(substr(str, RSTART, RLENGTH), a, "\x08");
c = a[1];
flag_bold = 0;
flag_underline = 0;
for (i = 2; i <= n; i++) {
if (a[i] == "_") {
if (c == "_" && !flag_bold)
flag_bold = 1;
else
flag_underline = 1;
} else {
if (a[i] == c)
flag_bold = 1;
else {
if (c == "_")
flag_underline = 1;
c = a[i];
}
}
}
if (flag_bold || flag_underline) {
prefix = "";
suffix = "";
if (flag_bold) {
prefix = "1";
suffix = "22";
}
if (flag_underline) {
prefix = prefix != "" ? prefix ";4" : "4";
suffix = suffix != "" ? suffix ";24" : "24";
}
c = "\x1b[" prefix "m" c "\x1b[" suffix "m";
}
head = head substr(str, 1, RSTART - 1) c;
str = substr(str, RSTART + RLENGTH);
}
return head str;
}
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);
gsub(/.\x08/, "", optarg);
} else {
key = optspec;
optarg = "";
suffix = " ";
}
if (key ~ /[^-+'"$_ble_complete_option_chars"']/) return "";
return key FS optarg FS suffix;
}
{
gsub(/\x1b\[[ -?]*[@-~]/, ""); # CSI seq
gsub(/\x1b[ -\/]*[0-~]/, ""); # ESC seq
gsub(/\t/, " "); # HT
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++)
entries_register("+" substr(cfg_plus_generate, i, 1) FS FS FS, 999);
}
function usage_parse(line, _, optspec, optspec1, option, optarg, n, i, o) {
while (match(line, /\[['"$_ble_term_space"']*([^][]|\[[^][]*\])+['"$_ble_term_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(/^['"$_ble_term_space"']+|['"$_ble_term_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 usage_generate(_, i) {
for (i = 0; i < g_usage_count; i++)
entries_register(g_usage[i] FS, 999);
}
cfg_usage {
if (NR <= 20 && (g_usage_start || $0 ~ /^[_a-zA-Z0-9]|^[^-'"$_ble_term_space"'][^'"$_ble_term_space"']*(: |)/) ) {
g_usage_start = 1;
usage_parse($0);
} else if (/^['"$_ble_term_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 help_flush(_, i, desc, prev_opt) {
if (g_help_indent < 0) return;
for (i = 0; i < g_help_keys_count; i++) {
desc = g_help_desc;
if (i > 0 && g_help_keys[i] ~ /^--/) {
prev_opt = g_help_keys[i - 1];
sub(/\034.*/, "", prev_opt);
if (prev_opt ~ /^-[^-]$/) {
desc = "\033[1m[\033[0;36m" prev_opt "\033[0;1m]\033[m " desc;
}
}
entries_register(g_help_keys[i] FS desc, g_help_score);
}
g_help_indent = -1;
g_help_keys_count = 0;
g_help_desc = "";
}
function help_start(keydef, _, key, keyinfo, keys, nkey, i, optarg) {
if (g_help_desc != "") help_flush();
g_help_indent = get_indent(keydef);
g_help_score = g_help_indent;
nkey = 0;
for (;;) {
sub(/^,?['"$_ble_term_space"']+/, "", keydef);
if (match(keydef, /^'"$rex_option"'/) <= 0) break;
key = substr(keydef, 1, RLENGTH);
keydef = substr(keydef, RLENGTH + 1);
sub(/[,'"$_ble_term_space"']$/, "", 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(/^['"$_ble_term_space"']+/, "", optarg);
if (optarg !~ /[A-Z]|<.+>/) optarg = "";
} else if (optarg != ""){
if (keys[i] ~ /^[-+].$/) {
optarg2 = optarg;
sub(/^\[=/, "[", optarg2);
sub(/^=/, "", optarg2);
sub(/^[^'"$_ble_term_space"'[]/, " &", optarg2);
keys[i] = keys[i] optarg2;
} else {
optarg2 = optarg;
if (optarg2 ~ /^\[[^:=]/)
sub(/^\[/, "[=", optarg2);
else if (optarg2 ~ /^[^:='"$_ble_term_space"'[]/)
optarg2 = " " optarg2;
keys[i] = keys[i] optarg2;
}
}
}
}
for (i = 0; i < nkey; i++)
if ((keyinfo = split_option_optarg_suffix(keys[i])) != "")
g_help_keys[g_help_keys_count++] = keyinfo;
}
function help_append_desc(desc) {
gsub(/^['"$_ble_term_space"']+|['"$_ble_term_space"']$/, "", desc);
if (desc == "") return;
desc = str_convert_bs2ansi(desc);
if (g_help_desc == "")
g_help_desc = desc;
else
g_help_desc = g_help_desc " " desc;
}
cfg_help && match($0, /^['"$_ble_term_space"']*'"$rex_option"'((['"$_ble_term_space"']['"$_ble_term_space"']?)?'"$rex_option"')*/) {
key = substr($0, 1, RLENGTH);
desc = substr($0, RLENGTH + 1);
if (desc ~ /^,/) next;
help_start(key);
help_append_desc(desc);
if (desc !~ /^['"$_ble_term_space"']/) g_help_score += 100;
next;
}
g_help_indent >= 0 {
sub(/['"$_ble_term_space"']+$/, "");
indent = get_indent($0);
if (indent <= g_help_indent)
help_flush();
else
help_append_desc($0);
}
END {
help_flush();
usage_generate();
generate_plus();
entries_dump();
}
' | ble/bin/sort -t "$_ble_term_FS" -k 1
ble/util/unlocal LC_COLLATE LC_ALL 2>/dev/null
}
function ble/complete/mandb:bash-completion/inject {
if ble/is-function _comp_compgen_help; then
ble/function#advice after _comp_compgen_help__get_help_lines 'ble/complete/mandb:bash-completion/_get_help_lines.advice' &&
{ ble/function#advice before _comp_complete_longopt 'ble/complete/mandb:bash-completion/_parse_help.advice "${ADVICE_WORDS[1]}"' ||
ble/function#advice before _comp_longopt 'ble/complete/mandb:bash-completion/_parse_help.advice "${ADVICE_WORDS[1]}"'; } &&
function ble/complete/mandb:bash-completion/inject { return 0; }
elif ble/is-function _parse_help; then
ble/function#advice before _parse_help 'ble/complete/mandb:bash-completion/_parse_help.advice "${ADVICE_WORDS[1]}" "${ADVICE_WORDS[2]}"' &&
ble/function#advice before _longopt 'ble/complete/mandb:bash-completion/_parse_help.advice "${ADVICE_WORDS[1]}"' &&
ble/function#advice before _parse_usage 'ble/complete/mandb:bash-completion/_parse_help.advice "${ADVICE_WORDS[1]}" "${ADVICE_WORDS[2]}"' &&
function ble/complete/mandb:bash-completion/inject { return 0; }
fi
} 2>/dev/null # _parse_help が別の枠組みで定義されている事がある? #D1900
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:bash-completion/.alloc-subcache {
ret=
[[ $_ble_attached ]] || return 1
local command=$1 hash=$2 opts=$3
if [[ :$opts: == *:dequote:* ]]; then
ble/syntax:bash/simple-word/safe-eval "$command" noglob:nonull &&
command=$ret
fi
[[ $command ]] || return 1
[[ $command == ble*/* ]] || command=${1##*/}
ble/string#hash-pjw "$args" 64; local hash=$ret
local lc_messages=${LC_ALL:-${LC_MESSAGES:-${LANG:-C}}}
local mandb_cache_dir=$_ble_base_cache/complete.mandb/${lc_messages//'/'/%}
ble/util/sprintf ret '%s.%014x' "$mandb_cache_dir/_parse_help.d/$command" "$hash"
[[ -s $ret && $ret -nt $_ble_base/lib/core-complete.sh ]] && return 1
ble/util/mkd "${ret%/*}"
}
function ble/complete/mandb:bash-completion/_parse_help.advice {
local cmd=$1 args=$2 func=$ADVICE_FUNCNAME
local command=${COMP_WORDS[0]-} hash="${ADVICE_WORDS[*]}" ret
ble/complete/mandb:bash-completion/.alloc-subcache "$command" "$hash" dequote || return 0
local subcache=$ret
local default_option=--help help_opts=
[[ $func == _parse_usage ]] &&
default_option=--usage help_opts=mandb-usage
if [[ ( $func == _parse_help || $func == _parse_usage ) && $cmd == - ]]; then
ble/complete/mandb:help/generate-cache "$help_opts" >| "$subcache"
LC_ALL= LC_COLLATE=C ble/bin/awk -F "$_ble_term_FS" '
BEGIN { entry_count = 0; }
{
entries[entry_count++] = $1;
desc = $4;
gsub(/\033\[[ -?]*[@-~]/, "", desc);
if (match(desc, /^\[[^]'"$_ble_term_space"'[]*\] /) > 0) { # #D1709 safe
short_opt = substr(desc, 2, RLENGTH - 3);
excludes[short_opt] =1;
}
}
END {
for (i = 0; i < entry_count; i++)
if (!excludes[entries[i]])
print entries[i];
}
' "$subcache" 2>/dev/null # suppress locale error #D1440
else
local cmd_args
ble/string#split-words cmd_args "${args:-$default_option}"
"$cmd" "${cmd_args[@]}" 2>&1 | ble/complete/mandb:help/generate-cache "$help_opts" >| "$subcache"
fi
}
function ble/complete/mandb:bash-completion/_get_help_lines.advice {
((${#_lines[@]})) || return 0
local cmd=${_comp_args[0]-${COMP_WORDS[0]-}} hash="${ADVICE_WORDS[*]}"
ble/complete/mandb:bash-completion/.alloc-subcache "$cmd" "$hash" dequote || return 0
local subcache=$ret
local help_opts=
[[ ${ADVICE_FUNCNAME[1]} == *_usage ]] && help_opts=mandb-usage
printf '%s\n' "${_lines[@]}" | ble/complete/mandb:help/generate-cache "$help_opts" >| "$subcache"
}
function ble/complete/mandb/generate-cache {
local command=${1##*/} opts=${2-}
[[ $command ]] || return 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/opts#extract-last-optarg "$opts" bin
local path=${ret:-"$1"}
ble/bin#has "$path"; }; 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 -x exclude=
ble/opts#extract-last-optarg "$cmdspec_opts" mandb-exclude && exclude=$ret
local fs=$_ble_term_FS
ble/bin/awk -F "$_ble_term_FS" '
BEGIN {
plus_count = 0;
nodesc_count = 0;
exclude = ENVIRON["exclude"];
}
function emit(name, entry) {
hash[name] = entry;
if (exclude != "" && name ~ exclude) return;
print entry;
}
$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] { emit($1, $0); }
END {
for (i = 0; i < nodesc_count; i++)
if (!hash[nodesc_name[i]])
emit(nodesc_name[i], 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";
emit(name, name FS optarg FS suffix FS desc);
}
}
' "${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/safe-eval "$word" noglob &&
ble/progcolor/stop-option#test "$ret" &&
return 1
done
return 0
}
function ble/complete/source:option {
local opts=$1
if [[ :$opts: == *:empty:* ]]; then
[[ ! $COMPV ]] || return 0
else
local rex='^-[-+'$_ble_complete_option_chars']*$|^\+[_'$_ble_complete_option_chars']*$'
[[ $COMPV =~ $rex ]] || return 0
fi
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
ble/complete/source:option/generate-for-command "${comp_words[@]::comp_cword}"
}
function ble/complete/source:option/generate-for-command {
local cmd=$1 prev_args
prev_args=("${@:2}")
local alias_checked=' '
while
local ret cmdv=$cmd
ble/syntax:bash/simple-word/safe-eval "$cmd" nonull && cmdv=$ret
! ble/complete/mandb/load-cache "$cmdv"
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[iword]}
done
local -a entries; entries=("${ret[@]}")
if [[ ${cmdv##*/} == git ]]; then
local isubcmd
for ((isubcmd=0;isubcmd<${#prev_args[@]};isubcmd++)); do
local subcmd=${prev_args[isubcmd]}
if ble/syntax:bash/simple-word/safe-eval "$subcmd"; then
((${#ret[@]}==0)) || continue
subcmd=$ret
fi
if [[ $subcmd != -* ]] && ble/complete/mandb/load-cache "git-$subcmd"; then
cmdv=git-$subcmd
entries=("${ret[@]}")
prev_args=("${prev_args[@]:isubcmd+1}")
break
fi
done
fi
local cmdspec_opts=
ble/cmdspec/opts#load "$cmdv"
ble/complete/source:option/.is-option-context "${prev_args[@]}" || return 1
local "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 checked
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%%$fs*}
[[ $CAND == "$COMPV"* ]] || continue
ble/complete/cand/yield mandb "$CAND" "$entry"
[[ $entry == *"$fs"*"$fs"*"$fs"?* ]] && has_desc=1
done
[[ $has_desc && :$opts: != *:empty:* ]] && 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/generate {
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"
if [[ $comp_opts != *:ble/default:* ]]; then
if [[ $comp_opts == *:dirnames:* ]]; then
ble/complete/source:dir; ext=$?
((ext==148||cand_count>old_cand_count)) && return "$ext"
fi
if [[ $comp_opts == *:default:* ]]; then
ble/complete/source:file; ext=$?
((ext==148||cand_count>old_cand_count)) && return "$ext"
fi
return "$ext"
fi
ble/complete/source:option; local ext=$?
((ext==148)) && return "$ext"
local old_cand_count_dirnames=$cand_count
if [[ $comp_opts == *:dirnames:* ]]; then
ble/complete/source:dir; ext=$?
((ext==148)) && return "$ext"
fi
if ((cand_count==old_cand_count_dirnames)); then
ble/complete/source:file; ext=$?
((ext==148)) && return "$ext"
fi
ble/complete/source:option empty; 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 checked
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
((cand_iloop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148
[[ -e $cand || -h $cand ]] || continue
[[ $FIGNORE ]] && ! ble/complete/.fignore/filter "$cand" && continue
ble/complete/cand/yield file_rhs "$prefix$cand" "$prefix"
done
fi
((cand_count>old_cand_count))
}
function ble/complete/source:argument {
local comp_opts=:ble/default:
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
ble/complete/source:argument/generate
local ext=$?
((ext==148)) && return 148
[[ $comp_opts == *:ble/default:* ]] || return "$ext"
ble/complete/source:sabbrev
}
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 checked
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 checked
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 checked
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 {
comp_fignore=()
local i=0 leaf tmp
ble/string#split tmp ':' "$FIGNORE"
for leaf in "${tmp[@]}"; do
[[ $leaf ]] && comp_fignore[i++]="$leaf"
done
}
function ble/complete/.fignore/filter {
local pat
for pat in "${comp_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
local path spec i s
ble/syntax:bash/simple-word/evaluate-path-spec "$reconstructed" '' noglob:fixlen="${simple_ibrace#*:}"
for ((i=0;i<${#spec[@]};i++)); do
s=${spec[i]}
[[ $s == "$comps_fixed" || $s == "$reconstructed" ]] && continue
ble/array#push comps_fixed "${#s}:${path[i]}"
done
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 start=${2:-0}
local i j=$start
local -a prop=() cand=() word=() show=() data=()
for ((i=start;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-Z0-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 {
local _ble_local_rlvars; ble/util/rlvar#load
ble/util/rlvar#test completion-ignore-case 0 && comp_type=${comp_type}:i
ble/util/rlvar#test visible-stats 0 && comp_type=${comp_type}:vstat
ble/util/rlvar#test mark-directories 1 && comp_type=${comp_type}:markdir
ble/util/rlvar#test mark-symlinked-directories 1 && comp_type=${comp_type}:marksymdir
ble/util/rlvar#test match-hidden-files 1 && comp_type=${comp_type}:match-hidden
ble/util/rlvar#test menu-complete-display-prefix 0 && comp_type=${comp_type}:menu-show-prefix
comp_type=$comp_type${bleopt_complete_menu_color:+:menu-color}
comp_type=$comp_type${bleopt_complete_menu_color_match:+:menu-color-match}
}
function ble/complete/candidates/generate {
local opts=$1
local flag_force_fignore=
local flag_source_filter=
local -a comp_fignore=()
if [[ $FIGNORE ]]; then
ble/complete/.fignore/prepare
((${#comp_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/completion/candidates/determine-common-prefix/.is-progcomp-raw {
((cand_count==1)) && [[ ${cand_pack[0]} == progcomp:*:ble/syntax-raw:* ]] || return 0
local "${_ble_complete_cand_varnames[@]/%/=}" # WA #D1570 checked
ble/complete/cand/unpack "${cand_pack[0]}"
[[ $DATA == *:ble/syntax-raw:* ]]
}
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
if ! ble/completion/candidates/determine-common-prefix/.is-progcomp-raw; then
ble/complete/candidates/determine-common-prefix/.apply-partial-comps
fi
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/safe-eval "$notilde$COMPS" reconstruct: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_menu_opts=
_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
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
if [[ :$bleopt_complete_menu_complete_opts: == *:insert-selection:* ]]; then
ble-edit/content/replace-limited "$_ble_complete_menu0_beg" "$_ble_edit_ind" "$insert"
((_ble_edit_ind=_ble_complete_menu0_beg+${#insert}))
fi
}
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_leave!=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
[[ :$opts: == *:init:* ]] && opts=$opts:update-items
if [[ :$opts: != *:update-items:* ]]; then
local comp_type=${_ble_complete_menu_comp[4]}
local cand_pack; cand_pack=("${_ble_complete_menu_items[@]}")
local menu_common_part=$_ble_complete_menu_common_part
fi
local menu_style=$_ble_complete_menu_style
local menu_opts=$_ble_complete_menu_opts
if [[ ! $_ble_complete_menu_style || :$opts: == *:init:* ]]; then
menu_style=$bleopt_complete_menu_style
menu_opts=
[[ :$bleopt_complete_menu_complete_opts: == *:hidden:* && :$opts: != *:show_menu:* ]] &&
menu_opts=$menu_opts:hidden
_ble_complete_menu_style=$menu_style
_ble_complete_menu_opts=$menu_opts
fi
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_construct_opts=$opts
[[ :$comp_type: == *:sync:* ]] &&
menu_construct_opts=$menu_construct_opts:sync
[[ :$_ble_complete_menu_opts: == *:hidden:* ]] &&
menu_construct_opts=$menu_construct_opts:hidden
ble/complete/menu#construct "$menu_construct_opts" || return "$?"
ble/complete/menu#show
case :$opts: in
(*:init:*)
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_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_comp=("$COMP1" "$COMP2" "$COMPS" "$COMPV" "$comp_type")
_ble_complete_menu_footprint=$footprint ;;
(*:update-context:*)
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 ;;
esac
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[@]/%/=}" # WA #D1570 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 [[ $bleopt_complete_skip_matched ]]; 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/awk0.available; then
local printf_format='%s\0' char_RS='"\0"' awk=ble/bin/awk0
else
local printf_format='%s\x1E' char_RS='"\x1E"' awk=ble/bin/awk
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" "$@" | "$awk" '
function starts_with(str, head) {
return substr(str, 1, length(head)) == head;
}
function islower(s) {
return s == tolower(s);
}
BEGIN {
RS = '"$char_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 = islower(value) ? 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 ret
ble/opts#extract-last-optarg "$opts" menu-style &&
[[ $ret ]] && ble/is-function ble/complete/menu-style:"$ret"/construct &&
local bleopt_complete_menu_style=$ret
case :$opts: in
(*:insert_*:*) ;;
(*:toggle_menu:*)
if [[ $_ble_complete_menu_active ]]; then
ble/widget/menu_complete/toggle-hidden
return 0
else
opts=$opts:show_menu
fi ;;
(*:show_menu:*) ;;
(*:enter_menu:*)
[[ $_ble_complete_menu_active && :$opts: != *:context=*:* ]] &&
ble/complete/menu-complete/enter "$opts" && return 0 ;;
(*)
if [[ $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 "$opts" && return 0
fi
[[ $WIDGET == "$LASTWIDGET" && $state != complete ]] && opts=$opts:enter_menu
fi ;;
esac
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 menu_show_opts=init
local cand_limit_reached=
if [[ $_ble_complete_menu_active && :$opts: != *:regenerate:* &&
:$opts: != *:context=*:* && ${#_ble_complete_menu_items[@]} -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
menu_show_opts=update-context:update-items
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:* || :$opts: == *:insert_unique:* && cand_count -eq 1 ]]; 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:show_menu"
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:insert_unique:$opts
}
function ble/widget/complete/.select-menu-with-arg {
[[ $bleopt_complete_menu_complete && $_ble_complete_menu_active ]] || return 1
local footprint; ble/complete/menu/get-footprint
[[ $footprint == "$_ble_complete_menu_footprint" ]] || return 1
local arg_opts= opts=$1
[[ :$opts: == *:enter-menu:* ]] && arg_opts=always
[[ :$opts: == *:nobell:* ]] && arg_opts=$arg_opts:nobell
ble/widget/menu/append-arg/.is-argument "$arg_opts" || return 1
ble/complete/menu-complete/enter
ble/widget/menu/append-arg "$arg_opts"
return 0
}
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[@]/%/=}" # WA #D1570 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 update-items || 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_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_items[@]} -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:{selection}/.invalidate "$beg" "$obeg"
ble/highlight/layer:{selection}/.invalidate "$end" "$oend"
else
ble/highlight/layer:{selection}/.invalidate "$beg" "$end"
fi
else
if [[ $obeg ]]; then
ble/highlight/layer:{selection}/.invalidate "$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_items[@]}>=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
if [[ :$opts: == *:insert_unique:* ]] && ((${#_ble_complete_menu_items[@]}==1)); then
ble/complete/menu#select 0
ble/decode/keymap/push menu_complete
ble/widget/menu_complete/exit complete
return 0
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}
if [[ :$bleopt_complete_menu_complete_opts: != *:insert-selection:* ]]; then
local "${_ble_complete_cand_varnames[@]/%/=}" # WA #D1570 checked
ble/complete/cand/unpack "${_ble_complete_menu_items[_ble_complete_menu_selected]}"
new=$INSERT
fi
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_page_icons[_ble_complete_menu_selected-_ble_complete_menu_page_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/redispatch
}
_ble_complete_menu_switch_styles=(align-nowrap desc linewise dense-nowrap)
function ble/widget/menu_complete/switch-style {
local menu_style
if [[ $1 && $1 != [-+] ]]; then
menu_style=$1
else
local ret nstyle=${#_ble_complete_menu_switch_styles[@]} shift=${1:-+}1
if ble/array#index _ble_complete_menu_switch_styles "$_ble_complete_menu_style"; then
((ret=(ret+shift+nstyle)%nstyle))
else
((ret=shift<0?nstyle-1:0))
fi
menu_style=${_ble_complete_menu_switch_styles[ret]}
fi
[[ $menu_style != "$_ble_complete_menu_style" ]] || return 0
_ble_complete_menu_style=$menu_style
bleopt complete_menu_style="$menu_style"
local sel=$_ble_complete_menu_selected
ble/complete/menu/show scroll="$sel"
ble/complete/menu#select "$sel"
}
function ble/widget/menu_complete/toggle-hidden {
if [[ :$_ble_complete_menu_opts: == *:hidden:* ]]; then
ble/opts#remove _ble_complete_menu_opts hidden
else
_ble_complete_menu_opts=$_ble_complete_menu_opts:hidden
fi
local sel=$_ble_complete_menu_selected
ble/complete/menu/show scroll="$sel"
ble/complete/menu#select "$sel"
}
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'
ble-bind -f 'C-x SP' 'menu_complete/toggle-hidden'
ble-bind -f 'C-x right' 'menu_complete/switch-style +'
ble-bind -f 'C-x C-n' 'menu_complete/switch-style +'
ble-bind -f 'C-x left' 'menu_complete/switch-style -'
ble-bind -f 'C-x C-p' 'menu_complete/switch-style -'
ble-bind -f 'C-x a' 'menu_complete/switch-style align-nowrap'
ble-bind -f 'C-x c' 'menu_complete/switch-style dense-nowrap'
ble-bind -f 'C-x d' 'menu_complete/switch-style desc'
ble-bind -f 'C-x l' 'menu_complete/switch-style linewise'
local key
for key in {,M-,C-}{0..9}; do
ble-bind -f "$key" 'menu/append-arg'
done
}
_ble_complete_menu_arg=
function ble/widget/menu/append-arg {
[[ ${LASTWIDGET%%' '*} == */append-arg ]] || _ble_complete_menu_arg=
local i=${#KEYS[@]}; ((i&&i--))
local flag=$((KEYS[i]&_ble_decode_MaskFlag))
if ! [[ :$1: == *:always:* || flag -ne 0 || $_ble_complete_menu_arg ]]; then
ble/widget/menu_complete/exit-default
return "$?"
fi
local code=$((KEYS[i]&_ble_decode_MaskChar))
((48<=code&&code<=57)) || return 1
local ret; ble/util/c2s "$code"; local ch=$ret
((_ble_complete_menu_arg=10#0$_ble_complete_menu_arg$ch))
local count=${#_ble_complete_menu_items[@]}
while ((_ble_complete_menu_arg>count)); do
((_ble_complete_menu_arg=10#0${_ble_complete_menu_arg:1}))
done
if ! ((_ble_complete_menu_arg)); then
[[ :$1: == *:nobell:* ]] ||
ble/widget/.bell 'menu: out of range'
return 0
fi
ble/complete/menu#select "$((_ble_complete_menu_arg-1))"
}
function ble/widget/menu/append-arg/.is-argument {
local i=${#KEYS[@]}; ((i&&i--))
local flag=$((KEYS[i]&_ble_decode_MaskFlag))
local code=$((KEYS[i]&_ble_decode_MaskChar))
[[ :$1: == *:always:* ]] || ((flag)) || return 1
((48<=code&&code<=57))
}
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/enter {
local type=$1 COMP1=$2 suggest=$3 cand=$4 word=$5 insert1=${6-$5} suffix=${7-}
local limit=$((bleopt_line_limit_length))
if ((limit&&${#_ble_edit_str}+${#suggest}>limit)); then
return 1
fi
local insert; ble-edit/content/replace-limited "$_ble_edit_ind" "$_ble_edit_ind" "$suggest" nobell
((_ble_edit_mark=_ble_edit_ind+${#suggest}))
_ble_complete_ac_type=$type
_ble_complete_ac_comp1=$COMP1
_ble_complete_ac_cand=$cand
_ble_complete_ac_word=$word
_ble_complete_ac_insert=$insert1
_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
return 0
}
function ble/complete/auto-complete/source:history/.search-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/histexpand/run' &>/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/histexpand/run' &>/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/source:history/.search-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/source:history/.impl {
local opts=$1
local searcher=.search-heavy
[[ :$opts: == *:light:* ]] && searcher=.search-light
local ret
((_ble_edit_ind==${#_ble_edit_str})) || return 1
ble/complete/auto-complete/source:history/"$searcher" "$_ble_edit_str" || return "$?" # 0, 1 or 148
local command=$ret
[[ $command == "$_ble_edit_str" ]] && return 1
ble/complete/auto-complete/enter h 0 "${command:${#_ble_edit_str}}" '' "$command"
}
function ble/complete/auto-complete/source:history {
[[ $bleopt_complete_auto_history ]] || return 1
ble/complete/auto-complete/source:history/.impl light; local ext=$?
((ext==0||ext==148)) && return "$ext"
[[ $_ble_history_prefix || $_ble_history_load_done ]] &&
ble/complete/auto-complete/source:history/.impl; local ext=$?
((ext==0||ext==148)) && return "$ext"
}
function ble/complete/auto-complete/source:syntax {
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]}"
local insert_beg=$COMP1 insert_end=$COMP2 insert_flags=
ble/complete/action:"$ACTION"/complete
fi
local type= suggest=
if [[ $insert == "$COMPS"* ]]; then
[[ ${comp_text:COMP1} == "$insert"* ]] && return 1
type=c
suggest="${insert:${#COMPS}}"
else
case :$comp_type: in
(*:a:*) type=a ;;
(*:m:*) type=m ;;
(*:A:*) type=A ;;
(*) type=r ;;
esac
suggest=" [$insert] "
fi
ble/complete/auto-complete/enter "$type" "$COMP1" "$suggest" "$cand" "$word" "$insert" "$suffix"
}
_ble_complete_auto_source=(history syntax)
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
local source
for source in "${_ble_complete_auto_source[@]}"; do
ble/complete/auto-complete/source:"$source"; local ext=$?
((ext==0)) && break
((ext==148)) && return "$ext"
done
}
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/magic-space|ble/widget/magic-slash) ;;
(ble/widget/complete|ble/widget/vi_imap/complete)
[[ :$bleopt_complete_auto_complete_opts: == *:suppress-after-complete:* ]] && return 0 ;;
(*) return 0 ;;
esac
[[ $_ble_edit_str ]] || return 0
ble/util/idle.sleep-until "$((_ble_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/magic-slash) ;;
(ble/widget/complete) ;;
(ble/widget/vi_imap/complete) ;;
(ble/widget/auto_complete/self-insert) ;;
(*) return 0 ;;
esac
[[ $_ble_edit_str ]] || return 0
local until=$((_ble_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/redispatch
}
function ble/widget/auto_complete/self-insert/.is-magic-space {
((${#KEYS[@]}==1)) || return 1
local ikeymap=$((${#_ble_decode_keymap_stack[@]}-1))
((ikeymap>=0)) || return 1
local dicthead=_ble_decode_${_ble_decode_keymap_stack[ikeymap]}_kmap_
builtin eval "local ent=\${$dicthead$_ble_decode_key__seq[KEYS[0]]-}"
local command=${ent#*:}
[[ $command == ble/widget/magic-space || $command == ble/widget/magic-slash ]]
}
function ble/widget/auto_complete/self-insert {
if [[ $_ble_edit_overwrite_mode ]] || ble/widget/auto_complete/self-insert/.is-magic-space; then
ble/widget/auto_complete/cancel-default
return "$?"
fi
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 == "$comps_new" ]] && 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/redispatch
fi
}
function ble/widget/auto_complete/@end {
if ((_ble_edit_mark!=${#_ble_edit_str})); then
ble/widget/auto_complete/cancel-default
else
ble/widget/auto_complete/"$@"
fi
}
function ble/widget/auto_complete/insert-on-end {
ble/widget/auto_complete/@end insert
}
function ble/widget/auto_complete/.insert-prefix {
local ins
if [[ $_ble_complete_ac_type == [ch] ]]; then
ins=${_ble_edit_str:_ble_edit_ind:_ble_edit_mark-_ble_edit_ind}
else
ins=$_ble_complete_ac_insert
fi
local ret
ble/complete/auto-complete/insert-prefix:"$1" "$ins" "${@:2}"
local prefix=$ret
[[ $prefix || ! $ins ]] || return 1
if [[ $_ble_complete_ac_type == [ch] ]]; then
if [[ $prefix == "$ins" ]]; then
ble/widget/auto_complete/insert
return 0
else
local ins=$prefix
((_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
if [[ $prefix == "$ins" ]]; then
ble/widget/auto_complete/insert
return 0
else
local ins=$prefix
_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/complete/auto-complete/insert-prefix:word {
local breaks=${bleopt_complete_auto_wordbreaks:-$_ble_term_IFS}
local rex='^['$breaks']*([^'$breaks']+['$breaks']*)?'
[[ $1 =~ $rex ]]
ret=$BASH_REMATCH
}
function ble/widget/auto_complete/insert-word {
ble/widget/auto_complete/.insert-prefix word
}
function ble/complete/auto-complete/insert-prefix:xword {
local wtype=$2 word_class word_set word_sep
ble/edit/word:"$wtype"/setup
local x=0 y=0
_ble_edit_str=$1 ble/edit/word/forward-range 1
ret=${1::y?y:${#1}}
}
function ble/widget/auto_complete/insert-eword { ble/widget/auto_complete/.insert-prefix xword eword; }
function ble/widget/auto_complete/insert-cword { ble/widget/auto_complete/.insert-prefix xword cword; }
function ble/widget/auto_complete/insert-uword { ble/widget/auto_complete/.insert-prefix xword uword; }
function ble/widget/auto_complete/insert-sword { ble/widget/auto_complete/.insert-prefix xword sword; }
function ble/widget/auto_complete/insert-fword { ble/widget/auto_complete/.insert-prefix xword fword; }
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/@end insert'
ble-bind -f right 'auto_complete/@end insert'
ble-bind -f C-e 'auto_complete/@end insert'
ble-bind -f end 'auto_complete/@end insert'
ble-bind -f M-f 'auto_complete/@end insert-cword'
ble-bind -f C-right 'auto_complete/@end insert-cword'
ble-bind -f M-right 'auto_complete/@end 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 != w ]] && option=$sgro'-'$type$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_complete_sabbrev_version++))
ble/gdict#set _ble_complete_sabbrev "$key" "$value"
}
function ble/complete/sabbrev/list {
local type=$1; shift
local keys ret; keys=("$@")
if ((${#keys[@]}==0)); then
if [[ $type ]]; then
local ret key
ble/gdict#keys _ble_complete_sabbrev
for key in "${ret[@]}"; do
ble/gdict#get _ble_complete_sabbrev "$key" && [[ $ret == "$type":* ]] || continue
ble/array#push keys "$key"
done
else
ble/gdict#keys _ble_complete_sabbrev
keys=("${ret[@]}")
fi
((${#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 {
local type=$1; shift
if (($#)); then
local key
for key; do
ble/gdict#unset _ble_complete_sabbrev "$key"
done
((_ble_complete_sabbrev_version++))
elif [[ $type ]]; then
local ret key
ble/gdict#keys _ble_complete_sabbrev
if ((${#ret[@]})); then
for key in "${ret[@]}"; do
ble/gdict#get _ble_complete_sabbrev "$key" && [[ $ret == "$type":* ]] || continue
ble/gdict#unset _ble_complete_sabbrev "$key"
done
((_ble_complete_sabbrev_version++))
fi
else
ble/gdict#clear _ble_complete_sabbrev
((_ble_complete_sabbrev_version++))
fi
return 0
}
function ble/complete/sabbrev#get {
local key=$1
ble/gdict#get _ble_complete_sabbrev "$key" &&
[[ ! ${2-} || $ret == ["$2"]:* ]]
}
function ble/complete/sabbrev#get-keys {
keys=()
local type=${1-} ret
ble/gdict#keys _ble_complete_sabbrev
if [[ $type ]]; then
local key
for key in "${ret[@]}"; do
ble/gdict#get _ble_complete_sabbrev "$key" &&
[[ $ret == ["$type"]:* ]] &&
ble/array#push keys "$key"
done
else
keys=("${ret[@]}")
fi
}
function ble/complete/sabbrev/wordwise.get-keys {
ble/complete/sabbrev#get-keys 'wm'
}
_ble_complete_sabbrev_suffix_regex=()
function ble/complete/sabbrev/suffix.construct-regex {
if [[ ${_ble_complete_sabbrev_suffix_regex[1]} != "$_ble_complete_sabbrev_version" ]]; then
local keys out=
ble/complete/sabbrev#get-keys 's'
if ((${#keys[@]})); then
local key
for key in "${keys[@]}"; do
if [[ $key ]]; then
ble/string#escape-for-extended-regex "$key"
out=${out:+$out'|'}$ret
fi
done
fi
_ble_complete_sabbrev_suffix_regex[0]=${out:+'\.('$out')$'}
_ble_complete_sabbrev_suffix_regex[1]=$_ble_complete_sabbrev_version
fi
ret=${_ble_complete_sabbrev_suffix_regex[0]}
[[ $ret ]]
}
function ble/complete/sabbrev/literal.find {
local str=$1 opts=$2
ble/complete/sabbrev#match "$str" 'il' "$opts"
}
function ble/complete/sabbrev/suffix.is-normal-command {
ble/bin#has "$1" ||
{ ble/util/joblist.check; jobs -- "$1" &>/dev/null; } ||
{ [[ -d $1 ]] && shopt -q autocd &>/dev/null; }
}
function ble/complete/sabbrev/suffix.find {
key1= ent1=
local file=$1 opts=$2 ret
[[ :$opts: != *:literal:* ]] &&
ble/syntax:bash/simple-word/safe-eval "$file" &&
file=$ret
[[ $file == *.* ]] || return 1
ble/complete/sabbrev/suffix.is-normal-command "$file" && return 1
ble/complete/sabbrev#match "$file" 's' "$opts"
}
function ble/complete/sabbrev#match {
key1= ent1=
local target=$1 type=$2 opts=$3 keys
ble/complete/sabbrev#get-keys "$type"
local key2 ent2 ret
for key2 in "${keys[@]}"; do
((${#key2}>${#key1})) || continue
ble/gdict#get _ble_complete_sabbrev "$key2" || continue; ent2=$ret
case $ent2 in
(i:*) [[ $target == *"$key2" ]] ;;
(l:*) [[ $target == *"$key2" ]] && ble/string#match "${target%"$key2"}" $'(^|\n)[ \t]*$' ;;
(s:*) [[ $target == *."$key2" ]] ;;
(*) [[ $target == "$key2" ]] ;;
esac || continue
[[ :$opts: == *:filter-by-patterns:* ]] &&
((${#patterns[@]})) &&
! ble/complete/string#match-patterns "$key2" "${patterns[@]}" &&
continue
key1=$key2 ent1=$ent2
done
[[ $key1 ]]
}
function ble/complete/sabbrev/read-arguments/.set-type {
local new_type
case $1 in
(--type=wordwise | -w) new_type=w ;;
(--type=dynamic | -m) new_type=m ;;
(--type=inline | -i) new_type=i ;;
(--type=linewise | -l) new_type=l ;;
(--type=suffix | -s) new_type=s ;;
(*)
ble/util/print "ble-sabbrev: unknown sabbrev type '${1#--type=}'." >&2
flags=E$flags
return 1 ;;
esac
if [[ $type && $type != "$new_type" ]]; then
ble/util/print "ble-sabbrev: arg $1: a conflicting sabbrev type (-$type) has already been specified." >&2
flags=E$flags
fi
type=$new_type
}
function ble/complete/sabbrev/read-arguments {
specs=() print=()
flags= type=
while (($#)); do
local arg=$1; shift
if [[ $flags != L && $arg == -* ]]; then
case $arg in
(--)
flags=L$flags ;;
(--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]} ;;
(--color=*)
ble/util/print "ble-sabbrev: unknown color type '$arg'." >&2
flags=E$flags ;;
(--type=*)
ble/complete/sabbrev/read-arguments/.set-type "$arg" ;;
(--type)
if ((!$#)); then
ble/util/print "ble-sabbrev: option argument for '$arg' is missing" >&2
flags=E$flags
else
ble/complete/sabbrev/read-arguments/.set-type "--type=$1"; shift
fi ;;
(--*)
ble/util/print "ble-sabbrev: unknown option '$arg'." >&2
flags=E$flags ;;
(-*)
local i n=${#arg} c
for ((i=1;i<n;i++)); do
c=${arg:i:1}
case $c in
([wmils]) ble/complete/sabbrev/read-arguments/.set-type "-$c" ;;
(r) flags=r$flags ;;
(*)
ble/util/print "ble-sabbrev: unknown option '-$c'." >&2
flags=E$flags ;;
esac
done ;;
esac
else
if [[ $arg == ?*=* ]]; then
ble/array#push specs "$arg"
else
ble/array#push print "$arg"
fi
fi
done
return 0
}
function ble/complete/sabbrev {
local flags type specs print
ble/complete/sabbrev/read-arguments "$@"
if [[ $flags == *H* || $flags == *E* ]]; then
[[ $flags == *E* ]] && ble/util/print
ble/util/print-lines \
'usage: ble-sabbrev [--type=TYPE|-wmils] [KEY=VALUE]...' \
'usage: ble-sabbrev [-r|--reset] [--type=TYPE|-wmils|KEY...]' \
'usage: ble-sabbrev [--color[=auto|always|never]] [--type=TYPE|-wmils|KEY...]' \
'usage: ble-sabbrev --help' \
' Register sabbrev expansion.' \
'' \
'OPTIONS' \
' -w, --type=wordwise replace matching word.' \
' -m, --type=dynamic run command and replace matching word.' \
' -i, --type=inline replace matching suffix.' \
' -l, --type=linewise replace matching line.' \
' -s, --type=suffix replace word with extension in the command position.' \
'' \
' -r, --reset remove specified set of sabbrev.' \
'' \
' --color=always enable color output.' \
' --color=never disable color output.' \
' --color, --color=auto automatically determine color output (default).' \
''
[[ ! $flags == *E* ]]; return "$?"
fi
local ext=0
if ((${#specs[@]}==0||${#print[@]})); then
if [[ $flags == *r* ]]; then
ble/complete/sabbrev/reset "$type" "${print[@]}"
else
ble/complete/sabbrev/list "$type" "${print[@]}"
fi || ext=$?
fi
local spec key value
for spec in "${specs[@]}"; do
key=${spec%%=*} value=${spec#*=}
ble/complete/sabbrev/register "$key" "${type:-w}:$value"
done
return "$ext"
}
function ble-sabbrev {
builtin eval -- "$_ble_bash_POSIXLY_CORRECT_local_adjust"
ble/complete/sabbrev "$@"
builtin eval -- "$_ble_bash_POSIXLY_CORRECT_local_return"
}
function ble/complete/sabbrev/locate-key {
pos=$comp_index
local rex_source_type='^('$1')$'
local sources src asrc
ble/complete/context:syntax/generate-sources
for src in "${sources[@]}"; do
ble/string#split-words asrc "$src"
[[ ${asrc[0]} =~ $rex_source_type ]] || continue
if [[ ${asrc[0]} == argument ]]; then
local wtype=$_ble_attr_VAR wbeg=${asrc[1]} wlen=$((comp_index-asrc[1])) ret
ble/syntax:bash/find-rhs "$wtype" "$wbeg" "$wlen" long-option &&
asrc[0]=rhs asrc[1]=$ret
fi
if [[ ${asrc[0]} == rhs ]]; then
local rex_element
ble/syntax:bash/simple-word/get-rex_element :
local rex='^:*('$rex_element':+)'
[[ ${_ble_edit_str:asrc[1]:comp_index-asrc[1]} =~ $rex ]] &&
((asrc[1]+=${#BASH_REMATCH}))
fi
((asrc[1]<pos)) && pos=${asrc[1]}
done
((pos<comp_index))
}
function ble/complete/sabbrev/expand {
local opts=$1
local comp_index=$_ble_edit_ind comp_text=$_ble_edit_str
[[ :$opts: == *:wordwise:* || :$opts: == *:literal:* || :$opts: == *:suffix:* ]] ||
opts=$opts:wordwise:literal:suffix
local -a patterns=()
local ret
ble/opts#extract-all-optargs "$opts" pattern &&
patterns=("${ret[@]}")
local key= ent= pos_wbegin=
if [[ :$opts: == *:wordwise:* ]]; then
local pos key1 ret
ble/complete/sabbrev/locate-key 'file|command|argument|variable:w|wordlist:.*|sabbrev|rhs' &&
key1=${_ble_edit_str:pos:comp_index-pos} &&
ble/complete/sabbrev#get "$key1" 'wm' &&
{ ((${#patterns[@]}==0)) || ble/complete/string#match-patterns "$key1" "${patterns[@]}"; } &&
((${#key1}>${#key})) && key=$key1 ent=$ret pos_wbegin=$pos
fi
if [[ :$opts: == *:suffix:* ]]; then
local pos key1 ent1
ble/complete/sabbrev/locate-key 'command' &&
ble/complete/sabbrev/suffix.find "${_ble_edit_str:pos:comp_index-pos}" filter-by-patterns &&
((${#key1}>${#key})) && key=$key1 ent=$ent1 pos_wbegin=$pos
fi
if [[ :$opts: == *:literal:* ]]; then
local key1 ent1
ble/complete/sabbrev/literal.find "${_ble_edit_str::comp_index}" filter-by-patterns &&
((${#key1}>${#key})) && key=$key1 ent=$ent1
fi
[[ $key ]] || return 1
local type=${ent%%:*} value=${ent#*:}
local exit=0
if [[ :$opts: == *:type-status:* ]]; then
local ret
ble/util/s2c "$type"
exit=$ret
fi
case $type in
([wil])
[[ :$opts: == *:strip-slash:* ]] && value=${value%/}
local pos=$((comp_index-${#key}))
ble/widget/.replace-range "$pos" "$comp_index" "$value"
((_ble_edit_ind=pos+${#value})) ;;
(s)
ble/widget/.replace-range "$pos_wbegin" "$pos_wbegin" "$value "
((_ble_edit_ind=comp_index+${#value}+1)) ;;
(m)
local pos=$pos_wbegin
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 checked
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]}
[[ :$opts: == *:strip-slash:* ]] && value=${value%/}
ble/widget/.replace-range "$pos" "$comp_index" "$value"
((_ble_edit_ind=pos+${#value}))
return "$exit"
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 init || return "$?"
[[ :$bleopt_sabbrev_menu_opts: == *:enter_menu:* ]] &&
ble/complete/menu-complete/enter "$bleopt_sabbrev_menu_opts"
return 147 ;;
(*) return 1 ;;
esac
return "$exit"
}
function ble/widget/sabbrev-expand {
ble/complete/sabbrev/expand; local ext=$?
((ext)) && ble/widget/.bell
return "$ext"
}
function ble/complete/action:sabbrev/initialize { CAND=$value; }
function ble/complete/action:sabbrev/complete { return 0; }
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 opts=$bleopt_complete_source_sabbrev_opts
[[ ! $COMPS && :$opts: == *:no-empty-completion:* ]] && return 1
local keys; ble/complete/sabbrev/wordwise.get-keys "$opts"
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 checked
ble/complete/cand/yield.initialize "$action"
for cand in "${keys[@]}"; do
ble/complete/candidates/filter#test "$cand" || continue
ble/complete/string#match-patterns "$cand" "${_ble_complete_source_sabbrev_ignore[@]}" && 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
}
function ble/complete/expand:alias {
local pos comp_index=$_ble_edit_ind comp_text=$_ble_edit_str
ble/complete/sabbrev/locate-key 'command'
((pos<comp_index)) || return 1
local word=${_ble_edit_str:pos:comp_index-pos}
local ret; ble/alias#expand "$word"
[[ $ret != "$word" ]] || return 1
ble/widget/.replace-range "$pos" "$comp_index" "$ret"
return 0
}
function ble/complete/expand:autocd {
local pos comp_index=$_ble_edit_ind comp_text=$_ble_edit_str
ble/complete/sabbrev/locate-key 'command'
((pos<comp_index)) || return 1
local word=${_ble_edit_str:pos:comp_index-pos} ret
ble/syntax:bash/simple-word/safe-eval "$word" nonull || return 1
local dir=$ret
[[ $dir && -d $dir ]] && ! ble/bin#has "$dir" || return 1
if [[ $dir == -* ]]; then
dir="cd -- $word"
else
dir="cd $word"
fi
ble/widget/.replace-range "$pos" "$comp_index" "$dir"
return 0
}
_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/redispatch
}
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'
}
ble/complete/action#inherit-from mandb.flag mandb
function ble/complete/action:mandb.flag/initialize {
ble/complete/action:mandb/initialize "$@"
}
function ble/complete/action:mandb.flag/init-menu-item {
ble/complete/action:mandb/init-menu-item
prefix=${CAND::!!PREFIX_LEN}
}
function ble/cmdinfo/complete/yield-flag {
local cmd=$1 flags=$2 opts=$3
[[ $COMPV != [!-]* && $COMPV != --* && $flags ]] || return 1
local "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 checked
ble/complete/cand/yield.initialize mandb
local ret
if [[ ${COMPV:1} ]] && ble/opts#extract-last-optarg "$opts" dedup "$flags"; then
local specified_flags=${ret//[!"${COMPV:1}"]}
flags=${flags//["$specified_flags"]}
fi
if ble/opts#extract-last-optarg "$opts" hasarg; then
[[ $COMPV == -*["$ret"]* ]] && return 1
fi
if [[ ! $flags ]]; then
[[ :$opts: == *:cancel-on-empty:* ]] && return 1
local "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 checked
ble/complete/cand/yield.initialize word
ble/complete/cand/yield word "$COMPV"
return "$?"
fi
local COMP_PREFIX=$COMPV
local has_desc=
if local ret; ble/complete/mandb/load-cache "$cmd"; then
local entry fs=$_ble_term_FS
for entry in "${ret[@]}"; do
((cand_iloop++%bleopt_complete_polling_cycle==0)) &&
ble/complete/check-cancel && return 148
local option=${entry%%$fs*}
[[ $option == -? && ${option:1} == ["$flags"] ]] || continue
ble/complete/cand/yield mandb.flag "$COMPV${option:1}" "$entry"
[[ $entry == *"$fs"*"$fs"*"$fs"?* ]] && has_desc=1
flags=${flags//${option:1}}
done
[[ $has_desc ]] && bleopt complete_menu_style=desc
fi
local i
for ((i=0;i<${#flags};i++)); do
ble/complete/cand/yield mandb.flag "$COMPV${flags:i:1}"
done
}
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/generate-cdable_vars {
shopt -q cdable_vars || return 1
ble/string#match "$COMPV" '^[_a-zA-Z0-9][_a-zA-Z0-9]*$' || return 1
local arr
ble/util/assign-array arr 'builtin compgen -vX "_ble*" -- "$COMPV"'
ble/complete/source/test-limit "${#arr[@]}" || return 1
local action=file old_cand_count=$cand_count
local cand "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 checked
ble/complete/cand/yield.initialize "$action"
for cand in "${arr[@]}"; do
((cand_iloop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148
[[ $cand == "$COMPV"?* && -d ${!cand-} ]] &&
ble/complete/cand/yield "$action" "$cand" "$data"
done
((cand_count>old_cand_count))
}
function ble/cmdinfo/complete:cd/.impl {
local type=$1
[[ $comps_flags == *v* ]] || return 1
local old_cand_count=$cand_count
case $type in
(pushd|popd|dirs)
if [[ $COMPV == [-+]* ]]; then
local flags=n
[[ $type == dirs ]] && flags=clpv
ble/cmdinfo/complete/yield-flag "$type" "$flags" dedup:hasarg=0123456789:cancel-on-empty
local "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 checked
ble/complete/cand/yield.initialize word
local ret
ble/color/face2sgr-ansi filename_directory
local sgr1=$ret sgr0=$'\e[m'
local i n=${#DIRSTACK[@]}
for ((i=0;i<n;i++)); do
local cand=${COMPV::1}$i
[[ $cand == "$COMPV"* ]] || continue
local j=$i; [[ $COMPV == -* ]] && j=$((n-1-i))
ble/complete/cand/yield word "$cand" "DIRSTACK[$j] $sgr1${DIRSTACK[j]}$sgr0"
done
if [[ $type == pushd ]]; then
[[ ${OLDPWD:-} && $COMPV == - ]] &&
ble/complete/cand/yield word - "OLDPWD $sgr1$OLDPWD$sgr0"
[[ -- == "$COMPV"* ]] &&
ble/complete/cand/yield word -- '(indicate the end of options)'
fi
((cand_count!=old_cand_count)) && return 0
fi
[[ $type == pushd ]] || return 0 ;;
(*)
if [[ $COMPV == -* ]]; then
local list=LP
((_ble_bash>=40200)) && list=${list}e
((_ble_bash>=40300)) && list=${list}@
ble/cmdinfo/complete/yield-flag cd "$list" dedup
local "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 checked
ble/complete/cand/yield.initialize word
if [[ ${OLDPWD:-} && $COMPV == - ]]; then
local ret
ble/color/face2sgr-ansi filename_directory
local sgr1=$ret sgr0=$'\e[m'
ble/complete/cand/yield word - "OLDPWD $sgr1$OLDPWD$sgr0"
fi
[[ -- == "$COMPV"* ]] &&
ble/complete/cand/yield word -- '(indicate the end of options)'
return 0
fi
esac
[[ :$comp_type: != *:[maA]:* && $COMPV =~ ^.+/ ]] && COMP_PREFIX=${BASH_REMATCH[0]}
[[ :$comp_type: == *:[maA]:* && ! $COMPV ]] && return 1
if [[ ! $CDPATH ]]; then
ble/complete/source:dir || return "$?"
((cand_count>old_cand_count)) && return 0
ble/cmdinfo/complete:cd/generate-cdable_vars
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[@]}"; local ext=$?
((ext==148)) && return "$ext"
[[ $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[@]}"; local ext=$?
((ext==148)) && return "$ext"
fi
((cand_count>old_cand_count)) && return 0
ble/cmdinfo/complete:cd/generate-cdable_vars
}
function ble/cmdinfo/complete:cd {
ble/cmdinfo/complete:cd/.impl cd
}
function ble/cmdinfo/complete:pushd {
ble/cmdinfo/complete:cd/.impl pushd
}
function ble/cmdinfo/complete:popd {
ble/cmdinfo/complete:cd/.impl popd
}
function ble/cmdinfo/complete:dirs {
ble/cmdinfo/complete:cd/.impl dirs
}
blehook/invoke complete_load
blehook complete_load=
return 0