# Copyright 2015 Koichi Murase . 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 ((l0;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 ((xcols&&(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)) ((wcell0&&x1+w>=cols)); then ((ncell=ncell_eol+cand_ncell)) elif ((x1+wncell_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=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=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=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;icolumnmax_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+1end)); 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=0&&!(visible_beg<=nsel&&nsel=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=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 ((oxcolumn)); 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=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=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]} ((y0)); 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()!^*?[]/, "\\\\&", 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;i0)); 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 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<>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=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;i1)); 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=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=0)); then ((DMAX0<=obeg?(obeg+=DMAX-DMAX0):(DMIN=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_ind0)) || 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&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]${#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=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=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