7520 lines
264 KiB
Bash
7520 lines
264 KiB
Bash
# 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
|