diff options
Diffstat (limited to '.local/src/blesh/lib')
22 files changed, 16257 insertions, 0 deletions
diff --git a/.local/src/blesh/lib/core-cmdspec.sh b/.local/src/blesh/lib/core-cmdspec.sh new file mode 100644 index 0000000..9da62a8 --- /dev/null +++ b/.local/src/blesh/lib/core-cmdspec.sh @@ -0,0 +1,66 @@ +# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license +function ble/cmdspec/initialize { return 0; } +function ble/complete/opts/initialize { + ble/cmdspec/opts mandb-help printf + ble/cmdspec/opts mandb-disable-man:mandb-help bind + ble/cmdspec/opts mandb-disable-man:mandb-help:mandb-help-usage complete + ble/cmdspec/opts mandb-disable-man:no-options : true false + ble/cmdspec/opts mandb-help=%'help echo':stop-options-unless='^-[neE]+$' echo + local conditional_operators=' + -eq (NUM1 -eq NUM2) Arithmetic comparison ==. + -ne (NUM1 -ne NUM2) Arithmetic comparison !=. + -lt (NUM1 -lt NUM2) Arithmetic comparison < . + -le (NUM1 -le NUM2) Arithmetic comparison <=. + -gt (NUM1 -gt NUM2) Arithmetic comparison > . + -ge (NUM1 -ge NUM2) Arithmetic comparison >=. + -nt (FILE1 -nt FILE2) True if file1 is newer than file2 (according to modification date). + -ot (FILE1 -ot FILE2) True if file1 is older than file2. + -ef (FILE1 -ef FILE2) True if file1 is a hard link to file2.' + ble/cmdspec/opts disable-double-hyphen:mandb-help=%'help test':mandb-help=@"$conditional_operators" '[[' + local test_operators=$conditional_operators' + -a (EXPR1 -a EXPR2) True if both expr1 AND expr2 are true. + -a (EXPR1 -o EXPR2) True if either expr1 OR expr2 is true.' + ble/cmdspec/opts disable-double-hyphen:mandb-help=%'help test':mandb-help=@"$test_operators" 'test' '[' + ble/cmdspec/opts mandb-disable-man:mandb-help:stop-options-postarg:plus-options=aAilnrtux declare typeset local + ble/cmdspec/opts mandb-disable-man:mandb-help:stop-options-postarg local export readonly + ble/cmdspec/opts mandb-disable-man:mandb-help:stop-options-postarg alias + ble/cmdspec/opts mandb-help rsync +} +ble/complete/opts/initialize +function ble/cmdinfo/cmd:declare/chroma.wattr { + local ret + if ((wtype==_ble_attr_VAR)); then + ble/syntax:bash/find-rhs "$wtype" "$wbeg" "$wlen" element-assignment && + ble/progcolor/highlight-filename.wattr "$ret" "$wend" + else + ble/progcolor/eval-word || return "$?" + local wval=$ret + if ble/string#match "$wval" '^([_a-zA-Z][_a-zA-Z0-9]*)(\[.+\])?$'; then + local varname=${BASH_REMATCH[1]} + ble/syntax/highlight/vartype "$varname" + ble/progcolor/wattr#setattr "$wbeg" "$ret" + ble/progcolor/wattr#setattr $((wbeg+${#varname})) d + elif ble/string#match "$wval" '^[-+]' && ble/progcolor/is-option-context; then + local ret; ble/color/face2g argument_option + ble/progcolor/wattr#setg "$wbeg" "$ret" + else + local ret; ble/color/face2g argument_error + ble/progcolor/wattr#setg "$wbeg" "$ret" + fi + fi + return 0 +} +function ble/cmdinfo/cmd:declare/chroma { + local i "${_ble_syntax_progcolor_vars[@]/%/=}" # WA #D1570 checked + for ((i=1;i<${#comp_words[@]};i++)); do + local ref=${tree_words[i]} + [[ $ref ]] || continue + local progcolor_iword=$i + ble/progcolor/load-word-data "$ref" + ble/progcolor/@wattr ble/cmdinfo/cmd:declare/chroma.wattr + done +} +function ble/cmdinfo/cmd:typeset/chroma { ble/cmdinfo/cmd:declare/chroma "$@"; } +function ble/cmdinfo/cmd:local/chroma { ble/cmdinfo/cmd:declare/chroma "$@"; } +function ble/cmdinfo/cmd:readonly/chroma { ble/cmdinfo/cmd:declare/chroma "$@"; } +function ble/cmdinfo/cmd:export/chroma { ble/cmdinfo/cmd:declare/chroma "$@"; } diff --git a/.local/src/blesh/lib/core-complete.sh b/.local/src/blesh/lib/core-complete.sh new file mode 100644 index 0000000..9d7c4c1 --- /dev/null +++ b/.local/src/blesh/lib/core-complete.sh @@ -0,0 +1,6327 @@ +# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license +ble/util/import "$_ble_base/lib/core-syntax.sh" +function ble/complete/string#search-longest-suffix-in { + local needle=$1 haystack=$2 + local l=0 u=${#needle} + while ((l<u)); do + local m=$(((l+u)/2)) + if [[ $haystack == *"${needle:m}"* ]]; then + u=$m + else + l=$((m+1)) + fi + done + ret=${needle:l} +} +function ble/complete/string#common-suffix-prefix { + local lhs=$1 rhs=$2 + if ((${#lhs}<${#rhs})); then + local i n=${#lhs} + for ((i=0;i<n;i++)); do + ret=${lhs:i} + [[ $rhs == "$ret"* ]] && return 0 + done + ret= + else + local j m=${#rhs} + for ((j=m;j>0;j--)); do + ret=${rhs::j} + [[ $lhs == *"$ret" ]] && return 0 + done + ret= + fi +} +function ble/complete/get-wordbreaks { + wordbreaks=$_ble_term_IFS$COMP_WORDBREAKS + [[ $wordbreaks == *'('* ]] && wordbreaks=${wordbreaks//['()']}'()' + [[ $wordbreaks == *']'* ]] && wordbreaks=']'${wordbreaks//']'} + [[ $wordbreaks == *'-'* ]] && wordbreaks=${wordbreaks//'-'}'-' +} +_ble_complete_menu_items=() +_ble_complete_menu_class= +_ble_complete_menu_param= +_ble_complete_menu_version= +_ble_complete_menu_page_style= +_ble_complete_menu_ipage= +_ble_complete_menu_offset= +_ble_complete_menu_icons=() +_ble_complete_menu_info_data=() +_ble_complete_menu_selected=-1 +function ble/complete/menu#check-cancel { + ((menu_iloop++%menu_interval==0)) && + [[ :$comp_type: != *:sync:* ]] && + ble/decode/has-input +} +_ble_complete_menu_style_measure=() +_ble_complete_menu_style_icons=() +_ble_complete_menu_style_pages=() +function ble/complete/menu#render-item { + if ble/is-function "$menu_class"/render-item; then + "$menu_class"/render-item "$@" + return "$?" + fi + local item=$1 opts=$2 + local sgr0=$_ble_term_sgr0 sgr1=$_ble_term_rev + [[ :$opts: == *:selected:* ]] && local sgr0=$sgr1 sgr1=$sgr0 + ble/canvas/trace-text "$item" nonewline:external-sgr + ret=$sgr0$ret$_ble_term_sgr0 +} +function ble/complete/menu-style:align/construct/.measure-candidates-in-page { + local max_wcell=$bleopt_menu_align_max; ((max_wcell>cols&&(max_wcell=cols))) + ((wcell=bleopt_menu_align_min,wcell<2&&(wcell=2))) + local ncell=0 index=$begin + local item ret esc1 w + for item in "${menu_items[@]:begin}"; do + ble/complete/menu#check-cancel && return 148 + local wcell_old=$wcell + local w=${_ble_complete_menu_style_measure[index]%%:*} + if [[ ! $w ]]; then + local x=0 y=0 + ble/complete/menu#render-item "$item"; esc1=$ret + local w=$((y*cols+x)) + _ble_complete_menu_style_measure[index]=$w:${#item}:$item$esc1 + fi + local wcell_request=$((w++,w<=max_wcell?w:max_wcell)) + ((wcell<wcell_request)) && wcell=$wcell_request + local line_ncell=$((cols/wcell)) + local cand_ncell=$(((w+wcell-1)/wcell)) + if [[ $menu_style == align-nowrap ]]; then + local x1=$((ncell%line_ncell*wcell)) + local ncell_eol=$(((ncell/line_ncell+1)*line_ncell)) + if ((x1>0&&x1+w>=cols)); then + ((ncell=ncell_eol+cand_ncell)) + elif ((x1+w<cols)); then + ((ncell+=cand_ncell)) + ((ncell>ncell_eol&&(ncell=ncell_eol))) + else + ((ncell+=cand_ncell)) + fi + else + ((ncell+=cand_ncell)) + fi + local max_ncell=$((line_ncell*lines)) + ((index&&ncell>max_ncell)) && { wcell=$wcell_old; break; } + ((index++)) + done + end=$index +} +function ble/complete/menu-style:align/construct-page { + x=0 y=0 esc= + local wcell=2 + ble/complete/menu-style:align/construct/.measure-candidates-in-page + (($?==148)) && return 148 + local ncell=$((cols/wcell)) + local index=$begin entry + for entry in "${_ble_complete_menu_style_measure[@]:begin:end-begin}"; do + ble/complete/menu#check-cancel && return 148 + local w=${entry%%:*}; entry=${entry#*:} + local s=${entry%%:*}; entry=${entry#*:} + local item=${entry::s} esc1=${entry:s} + local x0=$x y0=$y + if ((x==0||x+w<cols)); then + ((x+=w%cols,y+=w/cols)) + ((y>=lines&&(x=x0,y=y0,1))) && break + else + if [[ $menu_style == align-nowrap ]]; then + ((y+1>=lines)) && break + esc=$esc$'\n' + ((x0=x=0,y0=++y)) + ((x=w%cols,y+=w/cols)) + ((y>=lines&&(x=x0,y=y0,1))) && break + else + ble/complete/menu#render-item "$item" || + ((begin==index)) || # [Note: 少なくとも1個ははみ出ても表示する] + { x=$x0 y=$y0; break; }; esc1=$ret + fi + fi + _ble_complete_menu_style_icons[index]=$x0,$y0,$x,$y,${#item},${#esc1}:$item$esc1 + esc=$esc$esc1 + if ((++index<end)); then + local icell=$((x==0?0:(x+wcell)/wcell)) + if ((icell<ncell)); then + local pad=$((icell*wcell-x)) + ble/string#reserve-prototype "$pad" + esc=$esc${_ble_string_prototype::pad} + ((x=icell*wcell)) + else + ((y+1>=lines)) && break + esc=$esc$'\n' + ((x=0,++y)) + fi + fi + done + end=$index +} +function ble/complete/menu-style:align-nowrap/construct-page { + ble/complete/menu-style:align/construct-page "$@" +} +function ble/complete/menu-style:dense/construct-page { + x=0 y=0 esc= + local item index=$begin N=${#menu_items[@]} + for item in "${menu_items[@]:begin}"; do + ble/complete/menu#check-cancel && return 148 + local x0=$x y0=$y esc1 + ble/complete/menu#render-item "$item" || + ((index==begin)) || + { x=$x0 y=$y0; break; }; esc1=$ret + if [[ $menu_style == dense-nowrap ]]; then + if ((y>y0&&x>0||y>y0+1)); then + ((++y0>=lines)) && break + esc=$esc$'\n' + ((y=y0,x=x0=0)) + ble/complete/menu#render-item "$item" || + ((begin==index)) || + { x=$x0 y=$y0; break; }; esc1=$ret + fi + fi + _ble_complete_menu_style_icons[index]=$x0,$y0,$x,$y,${#item},${#esc1}:$item$esc1 + esc=$esc$esc1 + if ((++index<N)); then + if [[ $menu_style == dense-nowrap ]] && ((x==0)); then + : skip + elif ((x+1<cols)); then + esc=$esc' ' + ((x++)) + else + ((y+1>=lines)) && break + esc=$esc$'\n' + ((x=0,++y)) + fi + fi + done + end=$index +} +function ble/complete/menu-style:dense-nowrap/construct-page { + ble/complete/menu-style:dense/construct-page "$@" +} +function ble/complete/menu-style:linewise/construct-page { + local opts=$1 ret + local max_icon_width=$((cols-1)) + local prefix_format=$bleopt_menu_linewise_prefix prefix_width=0 + if [[ $prefix_format ]]; then + local prefix1 + ble/util/sprintf prefix1 "$prefix_format" ${#menu_items[@]} + local x1 y1 x2 y2 + LINES=1 COLUMNS=$max_icon_width x=0 y=0 ble/canvas/trace "$prefix1" truncate:measure-bbox + if ((x2<=max_icon_width/2)); then + prefix_width=$x2 + ble/string#reserve-prototype "$prefix_width" + fi + fi + local item x0 y0 esc1 index=$begin + end=$begin x=0 y=0 esc= + for item in "${menu_items[@]:begin:lines}"; do + ble/complete/menu#check-cancel && return 148 + if ((prefix_width)); then + local prefix1; ble/util/sprintf prefix1 "$prefix_format" $((index+1)) + LINES=1 COLUMNS=$max_icon_width y=0 ble/canvas/trace "$prefix1" truncate:relative:measure-bbox; esc1=$ret + if ((x<prefix_width)); then + x=$prefix_width + esc=$esc${_ble_string_prototype::prefix_width-x}$esc1 + else + esc=$esc$esc1 + fi + fi + ((x0=x,y0=y)) + lines=1 cols=$max_icon_width y=0 ble/complete/menu#render-item "$item"; esc1=$ret + _ble_complete_menu_style_icons[index]=$x0,$y0,$x,$y,${#item},${#esc1}:$item$esc1 + ((index++)) + esc=$esc$esc1 + ((y+1>=lines)) && break + ((x=0,++y)) + esc=$esc$'\n' + done + end=$index +} +function ble/complete/menu-style:linewise/guess { + ((ipage=scroll/lines, + begin=ipage*lines, + end=begin)) +} +_ble_complete_menu_desc_pageheight=() +function ble/complete/menu-style:desc/construct-page { + local opts=$1 ret + local opt_raw=; [[ $menu_style != desc-text ]] && opt_raw=1 + end=$begin esc= x=0 y=0 + local colsep=' | ' + local desc_sgr0=$'\e[m' + ble/color/face2sgr-ansi syntax_quoted; local desc_sgrq=$ret + ble/color/face2sgr-ansi syntax_delimiter; local desc_sgrt=$ret + local ncolumn=1 nline=$lines + local nrest_item=$((${#menu_items[@]}-begin)) + if [[ $bleopt_menu_desc_multicolumn_width ]]; then + ncolumn=$((cols/bleopt_menu_desc_multicolumn_width)) + if ((ncolumn<1)); then + ncolumn=1 + elif ((ncolumn>nrest_item)); then + ncolumn=$nrest_item + fi + fi + ((nline=(${#menu_items[@]}-begin+ncolumn-1)/ncolumn, + nline>lines&&(nline=lines))) + local ncolumn_max=$(((nrest_item+nline-1)/nline)) + ((ncolumn>ncolumn_max&&(ncolumn=ncolumn_max))) + local available_width=$cols + case $_ble_term_TERM in + (screen:*|tmux:*|kitty:*|contra:*) ;; + (*) ((available_width--)) ;; + esac + local wcolumn=$(((available_width-${#colsep}*(ncolumn-1))/ncolumn)) + local wcand_limit=$(((wcolumn+1)*2/3)) + ((wcand_limit<10&&(wcand_limit=wcolumn))) + local -a DRAW_BUFF=() + local index=$begin icolumn ymax=0 + for ((icolumn=0;icolumn<ncolumn;icolumn++)); do + local measure; measure=() + local pack w esc1 max_width=0 + for pack in "${menu_items[@]:index:nline}"; do + ble/complete/menu#check-cancel && return 148 + x=0 y=0 + lines=1 cols=$wcand_limit ble/complete/menu#render-item "$pack"; esc1=$ret + ((w=y*wcolumn+x,w>max_width&&(max_width=w))) + ble/array#push measure "$w:${#pack}:$pack$esc1" + done + local cand_width=$max_width + local desc_x=$((cand_width+1)); ((desc_x>wcolumn&&(desc_x=wcolumn))) + local desc_prefix=; ((wcolumn-desc_x>30)) && desc_prefix=': ' + local xcolumn=$((icolumn*(wcolumn+${#colsep}))) + x=0 y=0 + local entry w s pack esc1 x0 y0 pad + for entry in "${measure[@]}"; do + ble/complete/menu#check-cancel && return 148 + w=${entry%%:*} entry=${entry#*:} + s=${entry%%:*} entry=${entry#*:} + pack=${entry::s} esc1=${entry:s} + ((x0=x,y0=y,x+=w)) + _ble_complete_menu_style_icons[index]=$((xcolumn+x0)),$y0,$((xcolumn+x)),$y,${#pack},${#esc1},"0 0 $wcand_limit 1":$pack$esc1 + ((index++)) + ble/canvas/put.draw "$esc1" + ble/canvas/put-spaces.draw $((pad=desc_x-x)) + ble/canvas/put.draw "$desc_prefix" + ((x+=pad+${#desc_prefix})) + local desc=$desc_sgrt'(no description)'$desc_sgr0 + ble/function#try "$menu_class"/get-desc "$pack" + if [[ $opt_raw ]]; then + y=0 g=0 lc=0 lg=0 LINES=1 COLUMNS=$wcolumn ble/canvas/trace.draw "$desc" truncate:relative:ellipsis + else + y=0 lines=1 cols=$wcolumn ble/canvas/trace-text "$desc" nonewline + ble/canvas/put.draw "$ret" + fi + ble/canvas/put.draw "$_ble_term_sgr0" + ((y+1>=nline)) && break + ble/canvas/put-move.draw $((-x)) 1 + ((x=0,++y)) + done + ((y>ymax)) && ymax=$y + if ((icolumn+1<ncolumn)); then + ble/canvas/put-move.draw $((wcolumn-x)) $((-y)) + for ((y=0;y<=ymax;y++)); do + ble/canvas/put.draw "$colsep" + if ((y<ymax)); then + ble/canvas/put-move.draw -${#colsep} 1 + else + ble/canvas/put-move-y.draw $((-y)) + fi + done + else + ((y<ymax)) && ble/canvas/put-move-y.draw $((ymax-y)) + ((x+=xcolumn,y=ymax)) + fi + done + _ble_complete_menu_desc_pageheight[ipage]=$nline + end=$index + ble/canvas/sflush.draw -v esc +} +function ble/complete/menu-style:desc/guess { + local ncolumn=1 + if [[ $bleopt_menu_desc_multicolumn_width ]]; then + ncolumn=$((cols/bleopt_menu_desc_multicolumn_width)) + ((ncolumn<1)) && ncolumn=1 + fi + local nitem_per_page=$((ncolumn*lines)) + ((ipage=scroll/nitem_per_page, + begin=ipage*nitem_per_page, + end=begin)) +} +function ble/complete/menu-style:desc/locate { + local type=$1 osel=$2 + local ipage=$_ble_complete_menu_ipage + local nline=${_ble_complete_menu_desc_pageheight[ipage]:-1} + case $type in + (right) ((ret=osel+nline)) ;; + (left) ((ret=osel-nline)) ;; + (down) ((ret=osel+1)) ;; + (up) ((ret=osel-1)) ;; + (*) return 1 ;; + esac + local beg=$_ble_complete_menu_offset + local end=$((beg+${#_ble_complete_menu_icons[@]})) + if ((ret<beg)); then + ((ret=beg-1)) + elif ((ret>end)); then + ((ret=end)) + fi + return 0 +} +function ble/complete/menu-style:desc-text/construct-page { ble/complete/menu-style:desc/construct-page "$@"; } +function ble/complete/menu-style:desc-text/guess { ble/complete/menu-style:desc/guess; } +function ble/complete/menu-style:desc-text/locate { ble/complete/menu-style:desc/locate "$@"; } +function ble/complete/menu-style:desc-raw/construct-page { ble/complete/menu-style:desc/construct-page "$@"; } +function ble/complete/menu-style:desc-raw/guess { ble/complete/menu-style:desc/guess; } +function ble/complete/menu-style:desc-raw/locate { ble/complete/menu-style:desc/locate "$@"; } +function ble/complete/menu#construct/.initialize-size { + ble/edit/info/.initialize-size + local maxlines=$((bleopt_complete_menu_maxlines)) + ((maxlines>0&&lines>maxlines)) && lines=$maxlines +} +function ble/complete/menu#construct { + local menu_opts=$1 + local menu_iloop=0 + local menu_interval=$bleopt_complete_polling_cycle + local cols lines + ble/complete/menu#construct/.initialize-size + local nitem=${#menu_items[@]} + local version=$nitem:$lines:$cols + if ((nitem==0)); then + _ble_complete_menu_version=$version + _ble_complete_menu_items=() + _ble_complete_menu_page_style= + _ble_complete_menu_ipage=0 + _ble_complete_menu_offset=0 + _ble_complete_menu_icons=() + _ble_complete_menu_info_data=(ansi $'\e[38;5;242m(no items)\e[m') + _ble_complete_menu_selected=-1 + return 0 + fi + local scroll=0 rex=':scroll=([0-9]+):' use_cache= + if [[ :$menu_opts: =~ $rex ]]; then + scroll=${BASH_REMATCH[1]} + ((nitem&&(scroll%=nitem))) + [[ $_ble_complete_menu_version == $version ]] && use_cache=1 + fi + if [[ ! $use_cache ]]; then + _ble_complete_menu_style_measure=() + _ble_complete_menu_style_icons=() + _ble_complete_menu_style_pages=() + fi + local begin=0 end=0 ipage=0 x y esc + ble/function#try ble/complete/menu-style:"$menu_style"/guess + while ((end<nitem)); do + ((scroll<begin)) && return 1 + local page_data=${_ble_complete_menu_style_pages[ipage]} + if [[ $page_data ]]; then + local fields; ble/string#split fields , "${page_data%%:*}" + begin=${fields[0]} end=${fields[1]} + if ((begin<=scroll&&scroll<end)); then + x=${fields[2]} y=${fields[3]} esc=${page_data#*:} + break + fi + else + ble/complete/menu-style:"$menu_style"/construct-page "$menu_opts" || return "$?" + _ble_complete_menu_style_pages[ipage]=$begin,$end,$x,$y:$esc + ((begin<=scroll&&scroll<end)) && break + fi + begin=$end + ((ipage++)) + done + _ble_complete_menu_version=$version + _ble_complete_menu_items=("${menu_items[@]}") + _ble_complete_menu_class=$menu_class + _ble_complete_menu_param=$menu_param + _ble_complete_menu_page_style=$menu_style + _ble_complete_menu_ipage=$ipage + _ble_complete_menu_offset=$begin + _ble_complete_menu_icons=("${_ble_complete_menu_style_icons[@]:begin:end-begin}") + _ble_complete_menu_info_data=(store "$x" "$y" "$esc") + _ble_complete_menu_selected=-1 + return 0 +} +function ble/complete/menu#show { + ble/edit/info/immediate-show "${_ble_complete_menu_info_data[@]}" +} +function ble/complete/menu#clear { + ble/edit/info/default +} +function ble/complete/menu#select { + local menu_class=$_ble_complete_menu_class + local menu_param=$_ble_complete_menu_param + local osel=$_ble_complete_menu_selected nsel=$1 opts=$2 + local ncand=${#_ble_complete_menu_items[@]} + ((0<=osel&&osel<ncand)) || osel=-1 + ((0<=nsel&&nsel<ncand)) || nsel=-1 + ((osel==nsel)) && return 0 + local infox infoy + ble/canvas/panel#get-origin "$_ble_edit_info_panel" --prefix=info + local visible_beg=$_ble_complete_menu_offset + local visible_end=$((visible_beg+${#_ble_complete_menu_icons[@]})) + if ((nsel>=0&&!(visible_beg<=nsel&&nsel<visible_end))); then + ble/complete/menu/show filter:load-filtered-data:scroll="$nsel"; local ext=$? + ((ext)) && return "$ext" + if [[ $_ble_complete_menu_ipage ]]; then + local ipage=$_ble_complete_menu_ipage + ble/term/visible-bell "menu: Page $((ipage+1))" persistent + else + ble/term/visible-bell "menu: Offset $_ble_complete_menu_offset/$ncand" persistent + fi + visible_beg=$_ble_complete_menu_offset + visible_end=$((visible_beg+${#_ble_complete_menu_icons[@]})) + ((visible_end<=nsel&&(nsel=visible_end-1))) + ((nsel<=visible_beg&&(nsel=visible_beg))) + ((visible_beg<=osel&&osel<visible_end)) || osel=-1 + fi + local -a DRAW_BUFF=() + local ret; ble/canvas/panel/save-position; local pos0=$ret + if ((osel>=0)); then + local entry=${_ble_complete_menu_icons[osel-visible_beg]} + local fields text=${entry#*:} + ble/string#split fields , "${entry%%:*}" + if ((fields[3]<_ble_canvas_panel_height[_ble_edit_info_panel])); then + ble/canvas/panel#goto.draw "$_ble_edit_info_panel" "${fields[@]::2}" + ble/canvas/put.draw "${text:fields[4]}" + _ble_canvas_x=${fields[2]} _ble_canvas_y=$((infoy+fields[3])) + fi + fi + local value= + if ((nsel>=0)); then + [[ :$opts: == *:goto-page-top:* ]] && nsel=$visible_beg + local entry=${_ble_complete_menu_icons[nsel-visible_beg]} + local fields text=${entry#*:} + ble/string#split fields , "${entry%%:*}" + local x=${fields[0]} y=${fields[1]} + local item=${text::fields[4]} + local ret + if [[ ${fields[6]} ]]; then + local box cols lines + ble/string#split-words box "${fields[6]}" + x=${box[0]} y=${box[1]} cols=${box[2]} lines=${box[3]} + ble/complete/menu#render-item "$item" selected + ((x+=fields[0]-box[0])) + ((y+=fields[1]-box[1])) + else + local cols lines + ble/complete/menu#construct/.initialize-size + ble/complete/menu#render-item "$item" selected + fi + if ((y<_ble_canvas_panel_height[_ble_edit_info_panel])); then + ble/canvas/panel#goto.draw "$_ble_edit_info_panel" "${fields[@]::2}" + ble/canvas/put.draw "$ret" + _ble_canvas_x=$x _ble_canvas_y=$((infoy+y)) + fi + _ble_complete_menu_selected=$nsel + else + _ble_complete_menu_selected=-1 + value=$_ble_complete_menu_original + fi + ble/canvas/panel/load-position.draw "$pos0" + ble/canvas/bflush.draw + ble/function#try "$menu_class"/onselect "$nsel" "$osel" + return 0 +} +function ble/widget/menu/forward { + local opts=$1 + local nsel=$((_ble_complete_menu_selected+1)) + local ncand=${#_ble_complete_menu_items[@]} + if ((nsel>=ncand)); then + if [[ :$opts: == *:cyclic:* ]] && ((ncand>=2)); then + nsel=0 + else + ble/widget/.bell "menu: no more candidates" + return 1 + fi + fi + ble/complete/menu#select "$nsel" +} +function ble/widget/menu/backward { + local opts=$1 + local nsel=$((_ble_complete_menu_selected-1)) + if ((nsel<0)); then + local ncand=${#_ble_complete_menu_items[@]} + if [[ :$opts: == *:cyclic:* ]] && ((ncand>=2)); then + ((nsel=ncand-1)) + else + ble/widget/.bell "menu: no more candidates" + return 1 + fi + fi + ble/complete/menu#select "$nsel" +} +function ble/widget/menu/forward-column { + local osel=$((_ble_complete_menu_selected)) + if local ret; ble/function#try ble/complete/menu-style:"$_ble_complete_menu_page_style"/locate right "$osel"; then + local nsel=$ret ncand=${#_ble_complete_menu_items[@]} + if ((0<=nsel&&nsel<ncand&&nsel!=osel)); then + ble/complete/menu#select "$nsel" + else + ble/widget/.bell "menu: no more candidates" + fi + else + ble/widget/menu/forward + fi +} +function ble/widget/menu/backward-column { + local osel=$((_ble_complete_menu_selected)) + if local ret; ble/function#try ble/complete/menu-style:"$_ble_complete_menu_page_style"/locate left "$osel"; then + local nsel=$ret ncand=${#_ble_complete_menu_items[@]} + if ((0<=nsel&&nsel<ncand&&nsel!=osel)); then + ble/complete/menu#select "$nsel" + else + ble/widget/.bell "menu: no more candidates" + fi + else + ble/widget/menu/backward + fi +} +_ble_complete_menu_lastcolumn= +function ble/widget/menu/.check-last-column { + if [[ $_ble_complete_menu_lastcolumn ]]; then + local lastwidget=${LASTWIDGET%%' '*} + if [[ $lastwidget == ble/widget/menu/forward-line || + $lastwidget == ble/widget/menu/backward-line ]] + then + ox=$_ble_complete_menu_lastcolumn + return 0 + fi + fi + _ble_complete_menu_lastcolumn=$ox +} +function ble/widget/menu/.goto-column { + local column=$1 + local offset=$_ble_complete_menu_offset + local osel=$_ble_complete_menu_selected + ((osel>=0)) || return 1 + local entry=${_ble_complete_menu_icons[osel-offset]} + local fields; ble/string#split fields , "${entry%%:*}" + local ox=${fields[0]} oy=${fields[1]} + local nsel=-1 + if ((ox<column)); then + nsel=$osel + for entry in "${_ble_complete_menu_icons[@]:osel+1-offset}"; do + ble/string#split fields , "${entry%%:*}" + local x=${fields[0]} y=${fields[1]} + ((y==oy&&x<=column)) || break + ((nsel++)) + done + elif ((ox>column)); then + local i=$osel + while ((--i>=offset)); do + entry=${_ble_complete_menu_icons[i-offset]} + ble/string#split fields , "${entry%%:*}" + local x=${fields[0]} y=${fields[1]} + ((y<oy||x<=column&&(nsel=i,1))) && break + done + fi + ((nsel>=0&&nsel!=osel)) && + ble/complete/menu#select "$nsel" +} +function ble/widget/menu/forward-line { + local offset=$_ble_complete_menu_offset + local osel=$_ble_complete_menu_selected + ((osel>=0)) || return 1 + local nsel=-1 goto_column= + if local ret; ble/function#try ble/complete/menu-style:"$_ble_complete_menu_page_style"/locate down "$osel"; then + nsel=$ret + else + local entry=${_ble_complete_menu_icons[osel-offset]} + local fields; ble/string#split fields , "${entry%%:*}" + local ox=${fields[0]} oy=${fields[1]} + ble/widget/menu/.check-last-column + local i=$osel nsel=-1 is_next_page= + for entry in "${_ble_complete_menu_icons[@]:osel+1-offset}"; do + ble/string#split fields , "${entry%%:*}" + local x=${fields[0]} y=${fields[1]} + ((y<=oy||y==oy+1&&x<=ox||nsel<0)) || break + ((++i,y>oy&&(nsel=i))) + done + ((nsel<0&&(is_next_page=1,nsel=offset+${#_ble_complete_menu_icons[@]}))) + ((is_next_page)) && goto_column=$ox + fi + local ncand=${#_ble_complete_menu_items[@]} + if ((0<=nsel&&nsel<ncand)); then + ble/complete/menu#select "$nsel" + [[ $goto_column ]] && ble/widget/menu/.goto-column "$goto_column" + return 0 + else + ble/widget/.bell 'menu: no more candidates' + return 1 + fi +} +function ble/widget/menu/backward-line { + local offset=$_ble_complete_menu_offset + local osel=$_ble_complete_menu_selected + ((osel>=0)) || return 1 + local nsel=-1 goto_column= + if local ret; ble/function#try ble/complete/menu-style:"$_ble_complete_menu_page_style"/locate up "$osel"; then + nsel=$ret + else + local entry=${_ble_complete_menu_icons[osel-offset]} + local fields; ble/string#split fields , "${entry%%:*}" + local ox=${fields[0]} oy=${fields[1]} + ble/widget/menu/.check-last-column + local nsel=$osel + while ((--nsel>=offset)); do + entry=${_ble_complete_menu_icons[nsel-offset]} + ble/string#split fields , "${entry%%:*}" + local x=${fields[0]} y=${fields[1]} + ((y<oy-1||y==oy-1&&x<=ox)) && break + done + ((0<=nsel&&nsel<offset)) && goto_column=$ox + fi + local ncand=${#_ble_complete_menu_items[@]} + if ((0<=nsel&&nsel<ncand)); then + ble/complete/menu#select "$nsel" + [[ $goto_column ]] && ble/widget/menu/.goto-column "$goto_column" + else + ble/widget/.bell 'menu: no more candidates' + return 1 + fi +} +function ble/widget/menu/backward-page { + if ((_ble_complete_menu_offset>0)); then + ble/complete/menu#select $((_ble_complete_menu_offset-1)) goto-page-top + else + ble/widget/.bell "menu: this is the first page." + return 1 + fi +} +function ble/widget/menu/forward-page { + local next=$((_ble_complete_menu_offset+${#_ble_complete_menu_icons[@]})) + if ((next<${#_ble_complete_menu_items[@]})); then + ble/complete/menu#select "$next" + else + ble/widget/.bell "menu: this is the last page." + return 1 + fi +} +function ble/widget/menu/beginning-of-page { + ble/complete/menu#select "$_ble_complete_menu_offset" +} +function ble/widget/menu/end-of-page { + local nicon=${#_ble_complete_menu_icons[@]} + ((nicon)) && ble/complete/menu#select $((_ble_complete_menu_offset+nicon-1)) +} +function ble/widget/menu/cancel { + ble/decode/keymap/pop + ble/complete/menu#clear + "$_ble_complete_menu_class"/oncancel +} +function ble/widget/menu/accept { + ble/decode/keymap/pop + ble/complete/menu#clear + local nsel=$_ble_complete_menu_selected + local hook=$_ble_complete_menu_accept_hook + _ble_complete_menu_accept_hook= + if ((nsel>=0)); then + "$_ble_complete_menu_class"/onaccept "$nsel" "${_ble_complete_menu_items[nsel]}" + else + "$_ble_complete_menu_class"/onaccept "$nsel" + fi +} +function ble-decode/keymap:menu/define { + ble-bind -f __default__ 'bell' + ble-bind -f __line_limit__ nop + ble-bind -f C-m 'menu/accept' + ble-bind -f RET 'menu/accept' + ble-bind -f C-g 'menu/cancel' + ble-bind -f 'C-x C-g' 'menu/cancel' + ble-bind -f 'C-M-g' 'menu/cancel' + ble-bind -f C-f 'menu/forward-column' + ble-bind -f right 'menu/forward-column' + ble-bind -f C-i 'menu/forward cyclic' + ble-bind -f TAB 'menu/forward cyclic' + ble-bind -f C-b 'menu/backward-column' + ble-bind -f left 'menu/backward-column' + ble-bind -f C-S-i 'menu/backward cyclic' + ble-bind -f S-TAB 'menu/backward cyclic' + ble-bind -f C-n 'menu/forward-line' + ble-bind -f down 'menu/forward-line' + ble-bind -f C-p 'menu/backward-line' + ble-bind -f up 'menu/backward-line' + ble-bind -f prior 'menu/backward-page' + ble-bind -f next 'menu/forward-page' + ble-bind -f home 'menu/beginning-of-page' + ble-bind -f end 'menu/end-of-page' +} +function ble/complete/menu.class/onaccept { + local hook=$_ble_complete_menu_accept_hook + _ble_complete_menu_accept_hook= + "$hook" "$@" +} +function ble/complete/menu.class/oncancel { + local hook=$_ble_complete_menu_cancel_hook + _ble_complete_menu_cancel_hook= + "$hook" "$@" +} +function ble/complete/menu#start { + _ble_complete_menu_accept_hook=$1; shift + _ble_complete_menu_cancel_hook= + local menu_style=linewise + local menu_items; menu_items=("$@") + local menu_class=ble/complete/menu.class menu_param= + ble/complete/menu#construct sync || return "$?" + ble/complete/menu#show + ble/complete/menu#select 0 + ble/decode/keymap/push menu + return 147 +} +function ble/complete/check-cancel { + [[ :$comp_type: != *:sync:* ]] && ble/decode/has-input +} +function ble/complete/string#escape-for-completion-context { + local str=$1 escape_flags=$2 + case $comps_flags in + (*S*) ble/string#escape-for-bash-single-quote "$str" ;; + (*E*) ble/string#escape-for-bash-escape-string "$str" ;; + (*[DI]*) ble/string#escape-for-bash-double-quote "$str" ;; + (*) + if [[ $comps_fixed ]]; then + ble/string#escape-for-bash-specialchars "$str" "b$escape_flags" + else + ble/string#escape-for-bash-specialchars "$str" "$escape_flags" + fi ;; + esac +} +function ble/complete/action/complete.addtail { + suffix=$suffix$1 +} +function ble/complete/action/complete.mark-directory { + [[ :$comp_type: == *:markdir:* && $CAND != */ ]] && + [[ ! -h $CAND || ( $insert == "$COMPS" || :$comp_type: == *:marksymdir:* ) ]] && + ble/complete/action/complete.addtail / +} +function ble/complete/action/complete.close-quotation { + case $comps_flags in + (*[SE]*) ble/complete/action/complete.addtail \' ;; + (*[DI]*) ble/complete/action/complete.addtail \" ;; + esac +} +_ble_complete_quote_insert_varnames=( + quote_action + quote_escape_flags + quote_cont_cutbackslash + quote_paramx_comps + quote_trav_prefix + quote_fixed_comps + quote_fixed_compv + quote_fixed_comps_len + quote_fixed_compv_len) +function ble/complete/action/quote-insert.initialize { + quote_action=$1 + quote_escape_flags=c + if [[ $quote_action == command ]]; then + quote_escape_flags= + elif [[ $quote_action == progcomp ]]; then + [[ $comp_opts != *:filenames:* ]] && + quote_escape_flags=${quote_escape_flags//c} + fi + [[ $comps_fixed ]] && quote_escape_flags=b$quote_escape_flags + quote_cont_cutbackslash= + [[ $comps_flags == *B* && $COMPS == *'\' ]] && + quote_cont_cutbackslash=1 + quote_paramx_comps=$COMPS + if [[ $comps_flags == *p* ]]; then + [[ $comps_flags == *B* && $quote_paramx_comps == *'\' ]] && + quote_paramx_comps=${quote_paramx_comps%'\'} + case $comps_flags in + (*[DI]*) + if [[ $COMPS =~ $rex_raw_paramx ]]; then + local rematch1=${BASH_REMATCH[1]} + quote_paramx_comps=$rematch1'${'${COMPS:${#rematch1}+1}'}' + else + quote_paramx_comps=$quote_paramx_comps'""' + fi ;; + (*) + quote_paramx_comps=$quote_paramx_comps'\' ;; + esac + fi + quote_trav_prefix= + case $comps_flags in + (*S*) quote_trav_prefix=\' ;; + (*E*) quote_trav_prefix=\$\' ;; + (*D*) quote_trav_prefix=\" ;; + (*I*) quote_trav_prefix=\$\" ;; + esac + quote_fixed_comps= + quote_fixed_compv= + quote_fixed_comps_len= + quote_fixed_compv_len= + if [[ $comps_fixed ]]; then + quote_fixed_compv=${comps_fixed#*:} + quote_fixed_compv_len=${#quote_fixed_compv} + quote_fixed_comps_len=${comps_fixed%%:*} + quote_fixed_comps=${COMPS::quote_fixed_comps_len} + fi +} +function ble/complete/action/quote-insert { + if [[ ! $quote_action ]]; then + local "${_ble_complete_quote_insert_varnames[@]/%/=}" # WA #D1570 safe + ble/complete/action/quote-insert.initialize "${1:-plain}" + fi + local escape_flags=$quote_escape_flags + if [[ $quote_action == command ]]; then + [[ $DATA == *:noquote:* || $COMPS == "$COMPV" && ( $CAND == '[[' || $CAND == '!' ) ]] && return 0 + elif [[ $quote_action == progcomp ]]; then + [[ $comp_opts == *:noquote:* ]] && return 0 + [[ $comp_opts == *:nospace:* && $CAND == *' ' && ! -f $CAND ]] && return 0 + [[ $CAND == '~'* && ! ( $comp_opts == *:filenames:* && -e $CAND ) ]] && + escape_flags=T$escape_flags + fi + if [[ $comps_flags == *v* && $CAND == "$COMPV"* ]]; then + local ins ret + ble/complete/string#escape-for-completion-context "${CAND:${#COMPV}}" "$escape_flags"; ins=$ret + if [[ $comps_flags == *p* && $ins == [_a-zA-Z0-9]* ]]; then + INSERT=$quote_paramx_comps$ins + else + [[ $quote_cont_cutbackslash ]] && ins=${ins#'\'} + INSERT=$COMPS$ins; + fi + elif [[ $quote_fixed_comps && $CAND == "$quote_fixed_compv"* ]]; then + local ret; ble/complete/string#escape-for-completion-context "${CAND:quote_fixed_compv_len}" "$escape_flags" + INSERT=$quote_fixed_comps$quote_trav_prefix$ret + else + local ret; ble/complete/string#escape-for-completion-context "$CAND" "$escape_flags" + INSERT=$quote_trav_prefix$ret + fi +} +function ble/complete/action/quote-insert.batch/awk { + local q=\' + local -x comp_opts=$comp_opts + local -x comps=$COMPS + local -x compv=$COMPV + local -x comps_flags=$comps_flags + local -x quote_action=$quote_action + local -x quote_escape_flags=$quote_escape_flags + local -x quote_paramx_comps=$quote_paramx_comps + local -x quote_cont_cutbackslash=$quote_cont_cutbackslash + local -x quote_trav_prefix=$quote_trav_prefix + local -x quote_fixed_comps=$quote_fixed_comps + local -x quote_fixed_compv=$quote_fixed_compv + "$quote_batch_awk" -v quote_batch_nulsep="$quote_batch_nulsep" -v q="$q" ' + function exists(filename) { return substr($0, 1, 1) == "1"; } + function is_file(filename) { return substr($0, 2, 1) == "1"; } + function initialize(_, flags, comp_opts, tmp) { + IS_XPG4 = AWKTYPE == "xpg4"; + REP_SL = "\\"; + if (IS_XPG4) REP_SL = "\\\\"; + REP_DBL_SL = "\\\\"; # gawk, nawk + sub(/.*/, REP_DBL_SL, tmp); + if (tmp == "\\") REP_DBL_SL = "\\\\\\\\"; # mawk, xpg4 + Q = q "\\" q q; + DELIM = 10; + if (quote_batch_nulsep != "") { + RS = "\0"; + DELIM = 0; + } + quote_action = ENVIRON["quote_action"]; + comps = ENVIRON["comps"]; + compv = ENVIRON["compv"]; + compv_len = length(compv); + comps_flags = ENVIRON["comps_flags"]; + escape_type = 0; + if (comps_flags ~ /S/) + escape_type = 1; + else if (comps_flags ~ /E/) + escape_type = 2; + else if (comps_flags ~ /[DI]/) + escape_type = 3; + else + escape_type = 4; + comps_v = (comps_flags ~ /v/); + comps_p = (comps_flags ~ /p/); + comp_opts = ENVIRON["comp_opts"]; + is_noquote = comp_opts ~ /:noquote:/; + is_nospace = comp_opts ~ /:nospace:/; + flags = ENVIRON["quote_escape_flags"]; + escape_c = (flags ~ /c/); + escape_b = (flags ~ /b/); + escape_tilde_always = 1; + escape_tilde_exists = 0; + if (quote_action == "progcomp") { + escape_tilde_always = 0; + escape_tilde_exists = (comp_opts ~ /:filenames:/); + } + quote_cont_cutbackslash = ENVIRON["quote_cont_cutbackslash"] != ""; + quote_paramx_comps = ENVIRON["quote_paramx_comps"]; + quote_trav_prefix = ENVIRON["quote_trav_prefix"]; + quote_fixed_comps = ENVIRON["quote_fixed_comps"]; + quote_fixed_compv = ENVIRON["quote_fixed_compv"]; + quote_fixed_comps_len = length(quote_fixed_comps); + quote_fixed_compv_len = length(quote_fixed_compv); + } + BEGIN { initialize(); } + function escape_for_completion_context(text) { + if (escape_type == 1) { + gsub(/'$q'/, Q, text); + } else if (escape_type == 2) { + if (text ~ /[\\'$q'\a\b\t\n\v\f\r\033]/) { + gsub(/\\/ , REP_DBL_SL, text); + gsub(/'$q'/, REP_SL q , text); + gsub(/\007/, REP_SL "a", text); + gsub(/\010/, REP_SL "b", text); + gsub(/\011/, REP_SL "t", text); + gsub(/\012/, REP_SL "n", text); + gsub(/\013/, REP_SL "v", text); + gsub(/\014/, REP_SL "f", text); + gsub(/\015/, REP_SL "r", text); + gsub(/\033/, REP_SL "e", text); + } + } else if (escape_type == 3) { + gsub(/[\\"$`]/, "\\\\&", text); # Note: All awks behaves the same for "\\\\&" + } else if (escape_type == 4) { + gsub(/[]\\ "'$q'`$|&;<>()!^*?[]/, "\\\\&", text); + if (escape_c) gsub(/[=:]/, "\\\\&", text); + if (escape_b) gsub(/[{,}]/, "\\\\&", text); + if (ret ~ /^~/ && (escape_tilde_always || escape_tilde_exists && exists(cand))) + text = "\\" text; + gsub(/\n/, "$" q REP_SL "n" q, text); + gsub(/\t/, "$" q REP_SL "t" q, text); + } + return text; + } + function quote_insert(cand) { + if (quote_action == "command") { + if (comps == compv && cand ~ /^(\[\[|]]|!)$/) return cand; + } else if (quote_action == "progcomp") { + if (is_noquote) return cand; + if (is_nospace && cand ~ / $/ && !is_file(cand)) return cand; + } + if (comps_v && substr(cand, 1, compv_len) == compv) { + ins = escape_for_completion_context(substr(cand, compv_len + 1)); + if (comps_p && ins ~ /^[_a-zA-Z0-9]/) { + return quote_paramx_comps ins; + } else { + if (quote_cont_cutbackslash) sub(/^\\/, "", ins); + return comps ins; + } + } else if (quote_fixed_comps_len && substr(cand, 1, quote_fixed_compv_len) == quote_fixed_compv) { + ins = substr(cand, quote_fixed_compv_len + 1); + return quote_fixed_comps quote_trav_prefix escape_for_completion_context(ins); + } else { + return quote_trav_prefix escape_for_completion_context(cand); + } + } + { + cand = substr($0, 3); + insert = quote_insert(cand); + printf("%s%c", insert, DELIM); + } + ' +} +function ble/complete/action/quote-insert.batch/proc { + local _ble_local_tmpfile; ble/util/assign/.mktmp + local delim='\n' + [[ $quote_batch_nulsep ]] && delim='\0' + if [[ $quote_action == progcomp ]]; then + local cand file exist + for cand in "${cands[@]}"; do + ((cand_iloop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148 + f=0 e=0 + [[ -e $cand ]] && e=1 + [[ -f $cand ]] && f=1 + printf "$e$f%s$delim" "$cand" + done + else + printf "00%s$delim" "${cands[@]}" + fi >| "$_ble_local_tmpfile" + local fname_cands=$_ble_local_tmpfile + ble/util/conditional-sync \ + 'ble/complete/action/quote-insert.batch/awk < "$fname_cands"' \ + '! ble/complete/check-cancel < /dev/tty' '' progressive-weight + local ext=$? + ble/util/assign/.rmtmp + return "$ext" +} +function ble/complete/action/quote-insert.batch { + local opts=$1 + local quote_batch_nulsep= + local quote_batch_awk=ble/bin/awk + if [[ :$opts: != *:newline:* ]]; then + if ((_ble_bash>=40400)); then + if [[ $_ble_bin_awk_type == [mg]awk ]]; then + quote_batch_nulsep=1 + elif ble/bin#has mawk; then + quote_batch_nulsep=1 + quote_batch_awk=mawk + elif ble/bin#has gawk; then + quote_batch_nulsep=1 + quote_batch_awk=gawk + fi + fi + [[ ! $quote_batch_nulsep ]] && + [[ "${cands[*]}" == *$'\n'* ]] && + return 1 + fi + if [[ $quote_batch_nulsep ]]; then + ble/util/assign-array0 inserts ble/complete/action/quote-insert.batch/proc + else + ble/util/assign-array inserts ble/complete/action/quote-insert.batch/proc + fi + return $? +} +function ble/complete/action/requote-final-insert { + local comps_prefix= check_optarg= + if [[ $insert == "$COMPS"* ]]; then + [[ $comps_flags == *[SEDI]* ]] && return 0 + [[ $COMPS != *[!':/={,'] ]] && comps_prefix=$COMPS + check_optarg=$COMPS + else + check_optarg=$insert + fi + if [[ $check_optarg ]]; then + if ble/string#match "$check_optarg" '^([_a-zA-Z][_a-zA-Z0-9]*|-[-a-zA-Z0-9.]+)=(([^\'\''"`${}]*|\\.)*:)?'; then + comps_prefix=$BASH_REMATCH + elif [[ $COMP_PREFIX == -[!'-=:/\'\''"$`{};&|<>!^{}'] && $check_optarg == "$COMP_PREFIX"* ]]; then + comps_prefix=${check_optarg::2} + fi + fi + if [[ $comps_fixed ]]; then + local comps_fixed_part=${COMPS::${comps_fixed%%:*}} + [[ $comps_prefix == "$comps_fixed_part"* ]] || + comps_prefix=$comps_fixed_part + fi + if [[ $insert == "$comps_prefix"* && $comps_prefix != *[!':/={,'] ]]; then + local ret ins=${insert:${#comps_prefix}} + if ! ble/syntax:bash/simple-word/is-literal "$ins" && + ble/syntax:bash/simple-word/is-simple "$ins" && + ble/syntax:bash/simple-word/eval "$ins" && + ((${#ret[@]}==1)) + then + ble/string#quote-word "$ret" quote-empty + ((${#ret}<=${#ins})) || return 0 + insert=$comps_prefix$ret + [[ $insert == "$COMPS"* ]] || insert_flags=r$insert_flags # 遡って書き換えた + fi + fi + return 0 +} +function ble/complete/action#inherit-from { + local dst=$1 src=$2 + local member srcfunc dstfunc + for member in initialize{,.batch} complete getg get-desc; do + srcfunc=ble/complete/action:$src/$member + dstfunc=ble/complete/action:$dst/$member + ble/is-function "$srcfunc" && builtin eval "function $dstfunc { $srcfunc; }" + done +} +function ble/complete/action:plain/initialize { + ble/complete/action/quote-insert +} +function ble/complete/action:plain/initialize.batch { + ble/complete/action/quote-insert.batch +} +function ble/complete/action:plain/complete { + ble/complete/action/requote-final-insert +} +function ble/complete/action:literal-substr/initialize { :; } +function ble/complete/action:literal-substr/initialize.batch { inserts=("${cands[@]}"); } +function ble/complete/action:literal-substr/complete { :; } +function ble/complete/action:substr/initialize { + ble/complete/action/quote-insert +} +function ble/complete/action:substr/initialize.batch { + ble/complete/action/quote-insert.batch +} +function ble/complete/action:substr/complete { + ble/complete/action/requote-final-insert +} +function ble/complete/action:literal-word/initialize { :; } +function ble/complete/action:literal-word/initialize.batch { inserts=("${cands[@]}"); } +function ble/complete/action:literal-word/complete { + if [[ $comps_flags == *x* ]]; then + ble/complete/action/complete.addtail ',' + else + ble/complete/action/complete.addtail ' ' + fi +} +function ble/complete/action:word/initialize { + ble/complete/action/quote-insert +} +function ble/complete/action:word/initialize.batch { + ble/complete/action/quote-insert.batch +} +function ble/complete/action:word/complete { + ble/complete/action/requote-final-insert + ble/complete/action/complete.close-quotation + ble/complete/action:literal-word/complete +} +function ble/complete/action:word/get-desc { + [[ $DATA ]] && desc=$DATA +} +function ble/complete/action:file/initialize { + ble/complete/action/quote-insert +} +function ble/complete/action:file/initialize.batch { + ble/complete/action/quote-insert.batch +} +function ble/complete/action:file/complete { + ble/complete/action/requote-final-insert + if [[ -e $CAND || -h $CAND ]]; then + if [[ -d $CAND ]]; then + ble/complete/action/complete.mark-directory + else + ble/complete/action:word/complete + fi + fi +} +function ble/complete/action:file/init-menu-item { + ble/syntax/highlight/getg-from-filename "$CAND" + [[ $g ]] || { local ret; ble/color/face2g filename_warning; g=$ret; } + if [[ :$comp_type: == *:vstat:* ]]; then + if [[ -h $CAND ]]; then + suffix='@' + elif [[ -d $CAND ]]; then + suffix='/' + elif [[ -x $CAND ]]; then + suffix='*' + fi + fi +} +function ble/complete/action:file_rhs/initialize { + ble/complete/action:file/initialize +} +function ble/complete/action:file_rhs/initialize.batch { + ble/complete/action:file/initialize.batch +} +function ble/complete/action:file_rhs/complete { + CAND=${CAND:${#DATA}} ble/complete/action:file/complete +} +function ble/complete/action:file_rhs/init-menu-item { + CAND=${CAND:${#DATA}} ble/complete/action:file/init-menu-item +} +_ble_complete_action_file_desc[_ble_attr_FILE_LINK]='symbolic link' +_ble_complete_action_file_desc[_ble_attr_FILE_ORPHAN]='symbolic link (orphan)' +_ble_complete_action_file_desc[_ble_attr_FILE_DIR]='directory' +_ble_complete_action_file_desc[_ble_attr_FILE_STICKY]='directory (sticky)' +_ble_complete_action_file_desc[_ble_attr_FILE_SETUID]='file (setuid)' +_ble_complete_action_file_desc[_ble_attr_FILE_SETGID]='file (setgid)' +_ble_complete_action_file_desc[_ble_attr_FILE_EXEC]='file (executable)' +_ble_complete_action_file_desc[_ble_attr_FILE_FILE]='file' +_ble_complete_action_file_desc[_ble_attr_FILE_CHR]='character device' +_ble_complete_action_file_desc[_ble_attr_FILE_FIFO]='named pipe' +_ble_complete_action_file_desc[_ble_attr_FILE_SOCK]='socket' +_ble_complete_action_file_desc[_ble_attr_FILE_BLK]='block device' +_ble_complete_action_file_desc[_ble_attr_FILE_URL]='URL' +function ble/complete/action:file/get-desc { + local type; ble/syntax/highlight/filetype "$CAND" + desc=${_ble_complete_action_file_desc[type]:-'file (???)'} +} +function ble/complete/action:progcomp/initialize/.reconstruct-from-noquote { + local simple_flags simple_ibrace ret count + ble/syntax:bash/simple-word/is-simple-or-open-simple "$INSERT" && + ble/syntax:bash/simple-word/reconstruct-incomplete-word "$INSERT" && + ble/complete/source/eval-simple-word "$ret" single:count && + ((count==1)) || return 0 + CAND=$ret + if [[ $quote_fixed_comps && $CAND == "$quote_fixed_compv"* ]]; then + local ret; ble/complete/string#escape-for-completion-context "${CAND:quote_fixed_compv_len}" "$escape_flags" + INSERT=$quote_fixed_comps$quote_trav_prefix$ret + return 3 + fi + return 0 +} +function ble/complete/action:progcomp/initialize { + if [[ :$DATA: == *:noquote:* ]]; then + local progcomp_resolve_brace=$quote_fixed_comps + [[ :$DATA: == *:ble/syntax-raw:* ]] && progcomp_resolve_brace= + ble/complete/action:progcomp/initialize/.reconstruct-from-noquote + return 0 + else + ble/complete/action/quote-insert progcomp + fi +} +function ble/complete/action:progcomp/initialize.batch { + if [[ :$DATA: == *:noquote:* ]]; then + inserts=("${cands[@]}") + local progcomp_resolve_brace=$quote_fixed_comps + [[ :$DATA: == *:ble/syntax-raw:* ]] && progcomp_resolve_brace= + cands=() + local INSERT simple_flags simple_ibrace ret count icand=0 + for INSERT in "${inserts[@]}"; do + ((cand_iloop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148 + local CAND=$INSERT + ble/complete/action:progcomp/initialize/.reconstruct-from-noquote || + inserts[icand]=$INSERT # INSERT を上書きした時 ($?==3) + cands[icand++]=$CAND + done + else + ble/complete/action/quote-insert.batch newline + fi +} +function ble/complete/action:progcomp/complete { + if [[ $DATA == *:filenames:* ]]; then + ble/complete/action:file/complete + else + if [[ $DATA != *:ble/no-mark-directories:* && -d $CAND ]]; then + ble/complete/action/requote-final-insert + ble/complete/action/complete.mark-directory + else + ble/complete/action:word/complete + fi + fi + [[ $DATA == *:nospace:* ]] && suffix=${suffix%' '} + [[ $DATA == *:ble/no-mark-directories:* && -d $CAND ]] && suffix=${suffix%/} +} +function ble/complete/action:progcomp/init-menu-item { + if [[ $DATA == *:filenames:* ]]; then + ble/complete/action:file/init-menu-item + fi +} +function ble/complete/action:progcomp/get-desc { + if [[ $DATA == *:filenames:* ]]; then + ble/complete/action:file/get-desc + fi +} +function ble/complete/action:command/initialize { + ble/complete/action/quote-insert command +} +function ble/complete/action:command/initialize.batch { + ble/complete/action/quote-insert.batch newline +} +function ble/complete/action:command/complete { + if [[ -d $CAND ]]; then + ble/complete/action/complete.mark-directory + elif ! type "$CAND" &>/dev/null; then + if [[ $CAND == */ ]]; then + insert_flags=${insert_flags}n + fi + else + ble/complete/action:word/complete + fi +} +function ble/complete/action:command/init-menu-item { + if [[ -d $CAND ]]; then + local ret; ble/color/face2g filename_directory; g=$ret + else + local type + if [[ $CAND != "$INSERT" ]]; then + ble/syntax/highlight/cmdtype "$CAND" "$INSERT" + else + local type; ble/util/type type "$CAND" + ble/syntax/highlight/cmdtype1 "$type" "$CAND" + fi + if [[ $CAND == */ ]] && ((type==_ble_attr_ERR)); then + type=_ble_attr_CMD_FUNCTION + fi + ble/syntax/attr2g "$type" + fi +} +_ble_complete_action_command_desc[_ble_attr_CMD_BOLD]=builtin +_ble_complete_action_command_desc[_ble_attr_CMD_BUILTIN]=builtin +_ble_complete_action_command_desc[_ble_attr_CMD_ALIAS]=alias +_ble_complete_action_command_desc[_ble_attr_CMD_FUNCTION]=function +_ble_complete_action_command_desc[_ble_attr_CMD_FILE]=file +_ble_complete_action_command_desc[_ble_attr_KEYWORD]=command +_ble_complete_action_command_desc[_ble_attr_CMD_JOBS]=job +_ble_complete_action_command_desc[_ble_attr_ERR]='command ???' +_ble_complete_action_command_desc[_ble_attr_CMD_DIR]=directory +function ble/complete/action:command/get-desc { + local title= value= + if [[ -d $CAND ]]; then + title=directory + else + local type; ble/util/type type "$CAND" + ble/syntax/highlight/cmdtype1 "$type" "$CAND" + case $type in + ($_ble_attr_CMD_ALIAS) + local ret + ble/alias#expand "$CAND" + title=alias value=$ret ;; + ($_ble_attr_CMD_FILE) + local path; ble/util/assign path 'type -p -- "$CAND"' + [[ $path == ?*/"$CAND" ]] && path="from ${path%/"$CAND"}" + title=file value=$path ;; + ($_ble_attr_CMD_FUNCTION) + local source lineno + ble/function#get-source-and-lineno "$CAND" + local def; ble/function#getdef "$CAND" + ble/string#match "$def" '^[^()]*\(\)[[:space:]]*\{[[:space:]]+(.*[^[:space:]])[[:space:]]+\}[[:space:]]*$' && + def=${BASH_REMATCH[1]} # 関数の中身を抽出する + local ret sgr0=$'\e[27m' sgr1=$'\e[7m' # Note: sgr-ansi で生成 + lines=1 cols=${COLUMNS:-80} x=0 y=0 ble/canvas/trace-text "$def" external-sgr + title=function value="${source##*/}:$lineno $desc_sgrq$ret" ;; + ($_ble_attr_CMD_JOBS) + ble/util/joblist.check + local job; ble/util/assign job 'jobs -- "$CAND" 2>/dev/null' || job='???' + title=job value=${job:-(ambiguous)} ;; + ($_ble_attr_ERR) + if [[ $CAND == */ ]]; then + title='function namespace' + else + title=${_ble_complete_action_command_desc[_ble_attr_ERR]} + fi ;; + (*) + title=${_ble_complete_action_command_desc[type]:-'???'} ;; + esac + fi + desc=${title:+$desc_sgrt($title)$desc_sgr0}${value:+ $value} +} +function ble/complete/action:variable/initialize { ble/complete/action/quote-insert; } +function ble/complete/action:variable/initialize.batch { ble/complete/action/quote-insert.batch newline; } +function ble/complete/action:variable/complete { + case $DATA in + (assignment) + ble/complete/action/complete.addtail '=' ;; + (braced) + ble/complete/action/complete.addtail '}' ;; + (word) ble/complete/action:word/complete ;; + (arithmetic|nosuffix) ;; # do nothing + esac +} +function ble/complete/action:variable/init-menu-item { + local ret; ble/color/face2g syntax_varname; g=$ret +} +function ble/complete/action:variable/get-desc { + local _ble_local_title=variable + if ble/is-array "$CAND"; then + _ble_local_title=array + elif ble/is-assoc "$CAND"; then + _ble_local_title=assoc + fi + local _ble_local_value= + if [[ $_ble_local_title == array || $_ble_local_title == assoc ]]; then + builtin eval "local count=\${#$CAND[@]}" + if ((count==0)); then + count=empty + else + count="$count items" + fi + _ble_local_value=$'\e[94m['$count$']\e[m' + else + local ret; ble/string#quote-word "${!CAND}" ansi:sgrq="$desc_sgrq":quote-empty + _ble_local_value=$ret + fi + desc="$desc_sgrt($_ble_local_title)$desc_sgr0 $_ble_local_value" +} +function ble/complete/source/test-limit { + local value=$1 limit= + if [[ :$comp_type: == *:auto_menu:* && $bleopt_complete_limit_auto_menu ]]; then + limit=$bleopt_complete_limit_auto_menu + elif [[ :$comp_type: == *:auto:* && $bleopt_complete_limit_auto ]]; then + limit=$bleopt_complete_limit_auto + else + limit=$bleopt_complete_limit + fi + if [[ $limit && value -gt limit ]]; then + cand_limit_reached=1 + [[ :$comp_type: == *:auto_menu: ]] && cand_limit_reached=cancel + return 1 + else + return 0 + fi +} +function ble/complete/source/eval-simple-word { + local word=$1 opts=$2 + if [[ :$comp_type: != *:sync:* && :$opts: != *:noglob:* ]]; then + opts=$opts:stopcheck:cached + [[ :$comp_type: == *:auto:* && $bleopt_complete_timeout_auto ]] && + opts=$opts:timeout=$((bleopt_complete_timeout_auto)) + fi + ble/syntax:bash/simple-word/eval "$word" "$opts"; local ext=$? + ((ext==142)) && return 148 + return "$ext" +} +function ble/complete/source/evaluate-path-spec { + local word=$1 sep=$2 opts=$3 + if [[ :$comp_type: != *:sync:* && :$opts: != *:noglob:* ]]; then + opts=$opts:stopcheck:cached:single + [[ :$comp_type: == *:auto:* && $bleopt_complete_timeout_auto ]] && + opts=$opts:timeout=$((bleopt_complete_timeout_auto)) + fi + ble/syntax:bash/simple-word/evaluate-path-spec "$word" "$sep" "$opts"; local ext=$? + ((ext==142)) && return 148 + return "$ext" +} +function ble/complete/source/reduce-compv-for-ambiguous-match { + [[ :$comp_type: == *:[maA]:* ]] || return 0 + local comps=$COMPS compv=$COMPV + local comps_prefix= compv_prefix= + if [[ $comps_fixed ]]; then + comps_prefix=${comps::${comps_fixed%%:*}} + compv_prefix=${comps_fixed#*:} + compv=${COMPV:${#compv_prefix}} + fi + case $comps_flags in + (*S*) comps_prefix=$comps_prefix\' ;; + (*E*) comps_prefix=$comps_prefix\$\' ;; + (*D*) comps_prefix=$comps_prefix\" ;; + (*I*) comps_prefix=$comps_prefix\$\" ;; + esac + if [[ $compv && :$comp_type: == *:a:* ]]; then + compv=${compv::1} + ble/complete/string#escape-for-completion-context "$compv" + comps=$ret + else + compv= comps= + fi + COMPV=$compv_prefix$compv + COMPS=$comps_prefix$comps +} +_ble_complete_yield_varnames=("${_ble_complete_quote_insert_varnames[@]}") +function ble/complete/cand/yield.initialize { + ble/complete/action/quote-insert.initialize "$1" +} +function ble/complete/cand/yield { + local ACTION=$1 CAND=$2 DATA=$3 + [[ $flag_force_fignore ]] && ! ble/complete/.fignore/filter "$CAND" && return 0 + [[ $flag_source_filter ]] || ble/complete/candidates/filter#test "$CAND" || return 0 + local INSERT=$CAND + ble/complete/action:"$ACTION"/initialize || return "$?" + local PREFIX_LEN=0 + [[ $CAND == "$COMP_PREFIX"* ]] && PREFIX_LEN=${#COMP_PREFIX} + local icand + ((icand=cand_count++)) + cand_cand[icand]=$CAND + cand_word[icand]=$INSERT + cand_pack[icand]=$ACTION:${#CAND},${#INSERT},$PREFIX_LEN:$CAND$INSERT$DATA +} +function ble/complete/cand/yield.batch { + local ACTION=$1 DATA=$2 + local inserts threshold=500 + [[ $OSTYPE == cygwin* || $OSTYPE == msys* ]] && threshold=2000 + if ((${#cands[@]}>=threshold)) && ble/function#try ble/complete/action:"$ACTION"/initialize.batch; then + local i n=${#cands[@]} + for ((i=0;i<n;i++)); do + ((cand_iloop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148 + local CAND=${cands[i]} INSERT=${inserts[i]} + [[ $flag_force_fignore ]] && ! ble/complete/.fignore/filter "$CAND" && continue + [[ $flag_source_filter ]] || ble/complete/candidates/filter#test "$CAND" || continue + local PREFIX_LEN=0 + [[ $CAND == "$COMP_PREFIX"* ]] && PREFIX_LEN=${#COMP_PREFIX} + local icand + ((icand=cand_count++)) + cand_cand[icand]=$CAND + cand_word[icand]=$INSERT + cand_pack[icand]=$ACTION:${#CAND},${#INSERT},$PREFIX_LEN:$CAND$INSERT$DATA + done + else + local cand + for cand in "${cands[@]}"; do + ((cand_iloop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148 + ble/complete/cand/yield "$ACTION" "$cand" "$DATA" + done + fi +} +function ble/complete/cand/yield-filenames { + local action=$1; shift + local rex_hidden= + [[ :$comp_type: != *:match-hidden:* ]] && + rex_hidden=${COMPV:+'.{'${#COMPV}'}'}'(^|/)\.[^/]*$' + local -a cands=() + local cand icand=0 + for cand; do + ((cand_iloop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148 + [[ $rex_hidden && $cand =~ $rex_hidden ]] && continue + cands[icand++]=$cand + done + [[ $FIGNORE ]] && local flag_force_fignore=1 + local "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe + ble/complete/cand/yield.initialize "$action" + ble/complete/cand/yield.batch "$action" +} +_ble_complete_cand_varnames=(ACTION CAND INSERT DATA PREFIX_LEN) +function ble/complete/cand/unpack { + local pack=$1 + ACTION=${pack%%:*} pack=${pack#*:} + local text=${pack#*:} + IFS=, builtin eval 'pack=(${pack%%:*})' + CAND=${text::pack[0]} + INSERT=${text:pack[0]:pack[1]} + DATA=${text:pack[0]+pack[1]} + PREFIX_LEN=${pack[2]} +} +function ble/complete/source:none { return 0; } +function ble/complete/source:wordlist { + [[ $comps_flags == *v* ]] || return 1 + local COMPS=$COMPS COMPV=$COMPV + ble/complete/source/reduce-compv-for-ambiguous-match + [[ $COMPV =~ ^.+/ ]] && COMP_PREFIX=${BASH_REMATCH[0]} + local opt_raw= opt_noword= opt_sabbrev= + while (($#)) && [[ $1 == -* ]]; do + local arg=$1; shift + case $arg in + (--) break ;; + (--*) ;; # ignore + (-*) + local i iN=${#arg} + for ((i=1;i<iN;i++)); do + case ${arg:i:1} in + (r) opt_raw=1 ;; + (W) opt_noword=1 ;; + (s) opt_sabbrev=1 ;; + (*) ;; # ignore + esac + done ;; + esac + done + [[ $opt_sabbrev ]] && + ble/complete/source:sabbrev + local action=word + [[ $opt_noword ]] && action=substr + [[ $opt_raw ]] && action=literal-$action + local cand "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe + ble/complete/cand/yield.initialize "$action" + for cand; do + [[ $cand == "$COMPV"* ]] && ble/complete/cand/yield "$action" "$cand" + done +} +function ble/complete/source:command/.contract-by-slashes { + local slashes=${COMPV//[!'/']} + ble/bin/awk -F / -v baseNF=${#slashes} ' + function initialize_common() { + common_NF = NF; + for (i = 1; i <= NF; i++) common[i] = $i; + common_degeneracy = 1; + common0_NF = NF; + common0_str = $0; + } + function print_common(_, output) { + if (!common_NF) return; + if (common_degeneracy == 1) { + print common0_str; + common_NF = 0; + return; + } + output = common[1]; + for (i = 2; i <= common_NF; i++) + output = output "/" common[i]; + if (common_NF == common0_NF) print output; + print output "/"; + common_NF = 0; + } + { + if (NF <= baseNF + 1) { + print_common(); + print $0; + } else if (!common_NF) { + initialize_common(); + } else { + n = common_NF < NF ? common_NF : NF; + for (i = baseNF + 1; i <= n; i++) + if (common[i] != $i) break; + matched_length = i - 1; + if (matched_length <= baseNF) { + print_common(); + initialize_common(); + } else { + common_NF = matched_length; + common_degeneracy++; + } + } + } + END { print_common(); } + ' +} +function ble/complete/source:command/gen.1 { + local COMPS=$COMPS COMPV=$COMPV + ble/complete/source/reduce-compv-for-ambiguous-match + local slow_compgen= + if [[ ! $COMPV ]]; then + slow_compgen=1 + elif [[ $OSTYPE == cygwin* ]]; then + case $COMPV in + (?|cy*|x8*|i6*) + slow_compgen=1 ;; + esac + fi + if [[ $slow_compgen ]]; then + shopt -q no_empty_cmd_completion && return 0 + ble/util/conditional-sync \ + 'builtin compgen -c -- "$COMPV"' \ + '! ble/complete/check-cancel' 128 progressive-weight + else + builtin compgen -c -- "$COMPV" + fi + if [[ $COMPV == */* ]]; then + local q="'" Q="'\''" + local compv_quoted="'${COMPV//$q/$Q}'" + builtin compgen -A function -- "$compv_quoted" + fi +} +function ble/complete/source:command/gen { + if [[ :$comp_type: != *:[maA]:* && $bleopt_complete_contract_function_names ]]; then + ble/complete/source:command/gen.1 | + ble/complete/source:command/.contract-by-slashes + else + ble/complete/source:command/gen.1 + fi + if [[ $arg != *D* ]]; then + local ret + ble/complete/source:file/.construct-pathname-pattern "$COMPV" + ble/complete/util/eval-pathname-expansion "$ret/"; (($?==148)) && return 148 + ble/complete/source/test-limit ${#ret[@]} || return 1 + ((${#ret[@]})) && printf '%s\n' "${ret[@]}" + fi + if [[ ! $COMPV || $COMPV == %* ]]; then + local q="'" Q="'\''" + local compv_quoted=${COMPV#'%'} + compv_quoted="'${compv_quoted//$q/$Q}'" + builtin compgen -j -P % -- "$compv_quoted" + local i joblist; ble/util/joblist + local job_count=${#joblist[@]} + for i in "${!joblist[@]}"; do + if local rex='^\[([0-9]+)\]'; [[ ${joblist[i]} =~ $rex ]]; then + joblist[i]=%${BASH_REMATCH[1]} + else + builtin unset -v 'joblist[i]' + fi + done + joblist=("${joblist[@]}") + if ((job_count>0)); then + ble/array#push joblist %% %+ + ((job_count>=2)) && + ble/array#push joblist %- + fi + builtin compgen -W '"${joblist[@]}"' -- "$compv_quoted" + fi +} +function ble/complete/source:command { + [[ $comps_flags == *v* ]] || return 1 + [[ ! $COMPV ]] && shopt -q no_empty_cmd_completion && return 1 + [[ $COMPV =~ ^.+/ ]] && COMP_PREFIX=${BASH_REMATCH[0]} + local arg=$1 + { + local old_cand_count=$cand_count + local comp_opts=: + ble/complete/source:argument/.generate-user-defined-completion initial; local ext=$? + ((ext==148)) && return "$ext" + if ((ext==0)); then + ((cand_count>old_cand_count)) && return "$ext" + fi + } + ble/complete/source:sabbrev + local arr + local compgen + ble/util/assign compgen 'ble/complete/source:command/gen "$arg"' + [[ $compgen ]] || return 1 + ble/util/assign-array arr 'ble/bin/sort -u <<< "$compgen"' # 1 fork/exec + ble/complete/source/test-limit ${#arr[@]} || return 1 + local action=command "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe + ble/complete/cand/yield.initialize "$action" + local is_quoted= + [[ $COMPS != "$COMPV" ]] && is_quoted=1 + local rex_keyword='^(if|then|else|elif|fi|case|esac|for|select|while|until|do|done|function|time|[!{}]|\[\[|coproc|\]\]|in)$' + local expand_aliases= + shopt -q expand_aliases && expand_aliases=1 + local cand icand=0 cands + for cand in "${arr[@]}"; do + ((cand_iloop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148 + [[ $cand != */ && -d $cand ]] && ! type "$cand" &>/dev/null && continue + if [[ $is_quoted ]]; then + local disable_count= + [[ $cand =~ $rex_keyword ]] && ((disable_count++)) + [[ $expand_aliases ]] && ble/is-alias "$cand" && ((disable_count++)) + if [[ $disable_count ]]; then + local type; ble/util/type type "$cand" + ((${#type[@]}>disable_count)) || continue + fi + else + [[ $cand == ']]' || $cand == in ]] && + ! { [[ $expand_aliases ]] && ble/is-alias "$cand"; } && + continue + if [[ ! $expand_aliases ]]; then + ble/is-alias "$cand" && ! type "$cand" &>/dev/null && continue + fi + if ble/string#match "$cand" '[][*?{,}!^~#]' && ble/is-alias "$cand"; then + ble/complete/cand/yield "$action" "$cand" :noquote: + continue + fi + fi + cands[icand++]=$cand + done + ble/complete/cand/yield.batch "$action" +} +function ble/complete/util/eval-pathname-expansion/.print-def { + local pattern=$1 ret + IFS= builtin eval "ret=($pattern)" 2>/dev/null + ble/string#quote-words "${ret[@]}" + ble/util/print "ret=($ret)" +} +function ble/complete/util/eval-pathname-expansion { + local pattern=$1 + local -a dtor=() + if [[ -o noglob ]]; then + set +f + ble/array#push dtor 'set -f' + fi + if ! shopt -q nullglob; then + shopt -s nullglob + ble/array#push dtor 'shopt -u nullglob' + fi + if ! shopt -q dotglob; then + shopt -s dotglob + ble/array#push dtor 'shopt -u dotglob' + else + ble/array#push dtor 'shopt -s dotglob' + fi + if ! shopt -q extglob; then + shopt -s extglob + ble/array#push dtor 'shopt -u extglob' + fi + if [[ :$comp_type: == *:i:* ]]; then + if ! shopt -q nocaseglob; then + shopt -s nocaseglob + ble/array#push dtor 'shopt -u nocaseglob' + fi + else + if shopt -q nocaseglob; then + shopt -u nocaseglob + ble/array#push dtor 'shopt -s nocaseglob' + fi + fi + if ble/util/is-cygwin-slow-glob "$pattern"; then # Note: #D1168 + if shopt -q failglob &>/dev/null || shopt -q nullglob &>/dev/null; then + pattern= + else + set -f + ble/array#push dtor 'set +f' + fi + fi + if [[ $GLOBIGNORE ]]; then + local GLOBIGNORE_save=$GLOBIGNORE + GLOBIGNORE= + ble/array#push dtor 'GLOBIGNORE=$GLOBIGNORE_save' + fi + ble/array#reverse dtor + ret=() + if [[ :$comp_type: == *:sync:* ]]; then + IFS= builtin eval "ret=($pattern)" 2>/dev/null + else + local sync_command='ble/complete/util/eval-pathname-expansion/.print-def "$pattern"' + local sync_opts=progressive-weight + [[ :$comp_type: == *:auto:* && $bleopt_complete_timeout_auto ]] && + sync_opts=$sync_opts:timeout=$((bleopt_complete_timeout_auto)) + local def + ble/util/assign def 'ble/util/conditional-sync "$sync_command" "" "" "$sync_opts"' &>/dev/null; local ext=$? + if ((ext==148)) || ble/complete/check-cancel; then + ble/util/invoke-hook dtor + return 148 + fi + builtin eval -- "$def" + fi 2>&$_ble_util_fd_stderr + ble/util/invoke-hook dtor + return 0 +} +function ble/complete/source:file/.construct-ambiguous-pathname-pattern { + local path=$1 fixlen=${2:-1} + local pattern= i=0 j + local names; ble/string#split names / "$1" + local name + for name in "${names[@]}"; do + ((i++)) && pattern=$pattern/ + if [[ $name ]]; then + ble/string#quote-word "${name::fixlen}" + pattern=$pattern$ret* + for ((j=fixlen;j<${#name};j++)); do + ble/string#quote-word "${name:j:1}" + if [[ $_ble_bash -lt 50000 && $pattern == *\* ]]; then + pattern=$pattern'([!'$ret'])' + fi + pattern=$pattern$ret* + done + fi + done + [[ $pattern == *'*' ]] || pattern=$pattern* + ret=$pattern +} +function ble/complete/source:file/.construct-pathname-pattern { + local path=$1 pattern + case :$comp_type: in + (*:a:*) ble/complete/source:file/.construct-ambiguous-pathname-pattern "$path"; pattern=$ret ;; + (*:A:*) ble/complete/source:file/.construct-ambiguous-pathname-pattern "$path" 0; pattern=$ret ;; + (*:m:*) ble/string#quote-word "$path"; pattern=*$ret* ;; + (*) ble/string#quote-word "$path"; pattern=$ret* + esac + ret=$pattern +} +function ble/complete/source:file/.impl { + local opts=$1 + [[ $comps_flags == *v* ]] || return 1 + [[ :$comp_type: != *:[maA]:* && $COMPV =~ ^.+/ ]] && COMP_PREFIX=${BASH_REMATCH[0]} + [[ :$comp_type: == *:[maA]:* && ! $COMPV ]] && return 1 + ble/complete/source:tilde; local ext=$? + ((ext==148||ext==0)) && return "$ext" + local -a candidates=() + local ret + ble/complete/source:file/.construct-pathname-pattern "$COMPV" + [[ :$opts: == *:directory:* ]] && ret=$ret/ + ble/complete/util/eval-pathname-expansion "$ret"; (($?==148)) && return 148 + ble/complete/source/test-limit ${#ret[@]} || return 1 + if [[ :$opts: == *:directory:* ]]; then + candidates=("${ret[@]%/}") + else + candidates=("${ret[@]}") + fi + [[ :$opts: == *:no-fd:* ]] && + ble/array#remove-by-regex candidates '^[0-9]+-?$|^-$' + local flag_source_filter=1 + ble/complete/cand/yield-filenames file "${candidates[@]}" +} +function ble/complete/source:file { + ble/complete/source:file/.impl "$1" +} +function ble/complete/source:dir { + ble/complete/source:file/.impl "directory:$1" +} +function ble/complete/source:rhs { ble/complete/source:file; } +function ble/complete/action:tilde/initialize { + CAND=${CAND#\~} ble/complete/action/quote-insert + INSERT=\~$INSERT + local rex='^~[^/'\''"$`\!:]*$'; [[ $INSERT =~ $rex ]] +} +function ble/complete/action:tilde/complete { + ble/complete/action/complete.mark-directory +} +function ble/complete/action:tilde/init-menu-item { + local ret + ble/color/face2g filename_directory; g=$ret +} +function ble/complete/action:tilde/get-desc { + if [[ $CAND == '~+' ]]; then + desc='current directory (tilde expansion)' + elif [[ $CAND == '~-' ]]; then + desc='previous directory (tilde expansion)' + elif local rex='^~[0-9]$'; [[ $CAND =~ $rex ]]; then + desc='DIRSTACK directory (tilde expansion)' + else + desc='user directory (tilde expansion)' + fi +} +function ble/complete/source:tilde/.generate { + local pattern=${COMPS#\~} + [[ :$comp_type: == *:[maA]:* ]] && pattern= + builtin compgen -P \~ -u -- "$pattern" + printf '%s\n' '~' '~+' '~-' + local dirstack_max=$((${#DIRSTACK[@]}-1)) + ((dirstack_max>=0)) && + builtin eval "printf '%s\n' '~'{0..$dirstack_max}" +} +function ble/complete/source:tilde { + local rex='^~[^/'\''"$`\!:]*$'; [[ $COMPS =~ $rex ]] || return 1 + local compgen candidates + ble/util/assign compgen ble/complete/source:tilde/.generate + [[ $compgen ]] || return 1 + ble/util/assign-array candidates 'ble/bin/sort -u <<< "$compgen"' + local flag_source_filter=1 + if [[ $COMPS == '~'?* ]]; then + local filter_type=$comp_filter_type + [[ $filter_type == none ]] && filter_type=head + local comp_filter_type + local comp_filter_pattern + ble/complete/candidates/filter#init "$filter_type" "$COMPS" + ble/array#filter candidates ble/complete/candidates/filter#test + fi + ((${#candidates[@]})) || return 1 + local old_cand_count=$cand_count + ble/complete/cand/yield-filenames tilde "${candidates[@]}"; local ext=$? + return $((ext?ext:cand_count>old_cand_count)) +} +function ble/complete/source:fd { + IFS=: builtin eval 'local fdlist=":${_ble_util_openat_fdlist[*]}:"' + [[ $comp_filter_type == none ]] && + local comp_filter_type=head + local old_cand_count=$cand_count + local action=word "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe + ble/complete/cand/yield.initialize "$action" + ble/complete/cand/yield "$action" - + if [[ -d /proc/self/fd ]]; then + local ret + ble/complete/util/eval-pathname-expansion '/proc/self/fd/*' + local fd + for fd in "${ret[@]}"; do + fd=${fd#/proc/self/fd/} + [[ ${fd//[0-9]} ]] && continue + [[ $fdlist == *:"$fd":* ]] && continue + ble/complete/cand/yield "$action" "$fd" + ble/complete/cand/yield "$action" "$fd-" + done + else + local fd + for ((fd=0;fd<10;fd++)); do + ble/fd#is-open "$fd" || continue + ble/complete/cand/yield "$action" "$fd" + ble/complete/cand/yield "$action" "$fd-" + done + fi + return $((cand_count>old_cand_count)) +} +function ble/complete/progcomp/.compvar-initialize-wordbreaks { + local ifs=$_ble_term_IFS q=\'\" delim=';&|<>()' glob='[*?' hist='!^{' esc='`$\' + local escaped=$ifs$q$delim$glob$hist$esc + wordbreaks=${COMP_WORDBREAKS//[$escaped]} # =: +} +function ble/complete/progcomp/.compvar-perform-wordbreaks { + local word=$1 + if [[ ! $word ]]; then + ret=('') + return 0 + fi + ret=() + while local head=${word%%["$wordbreaks"]*}; [[ $head != $word ]]; do + ble/array#push ret "$head" + word=${word:${#head}} + head=${word%%[!"$wordbreaks"]*} + ble/array#push ret "$head" + word=${word:${#head}} + done + ble/array#push ret "$word" +} +function ble/complete/progcomp/.compvar-eval-word { + local opts=$2:single + if [[ :$opts: == *:noglob:* ]]; then + ble/syntax:bash/simple-word/eval "$1" "$opts" + else + [[ $bleopt_complete_timeout_compvar ]] && + opts=timeout=$((bleopt_complete_timeout_compvar)):retry-noglob-on-timeout:$opts + ble/complete/source/eval-simple-word "$1" "$opts" + fi +} +function ble/complete/progcomp/.compvar-generate-subwords/impl1 { + local word=$1 ret simple_flags simple_ibrace + if [[ $point ]]; then + local left=${word::point} right=${word:point} + else + local left=$word right= + local point= # hide + fi + ble/syntax:bash/simple-word/reconstruct-incomplete-word "$left" || return 1 + left=$ret + if [[ $right ]]; then + case $simple_flags in + (*I*) right=\$\"$right ;; + (*D*) right=\"$right ;; + (*E*) right=\$\'$right ;; + (*S*) right=\'$right ;; + (*B*) right=\\$right ;; + esac + ble/syntax:bash/simple-word/reconstruct-incomplete-word "$right" || return 1 + right=$ret + fi + point=0 words=() + local eval_opts=noglob + ((${#ret[@]}==1)) && eval_opts= + ble/syntax:bash/simple-word#break-word "$left" + local subword + for subword in "${ret[@]}"; do + ble/complete/progcomp/.compvar-eval-word "$subword" "$eval_opts" + ble/array#push words "$ret" + ((point+=${#ret})) + done + if [[ $right ]]; then + ble/syntax:bash/simple-word#break-word "$right" + local subword isfirst=1 + for subword in "${ret[@]}"; do + ble/complete/progcomp/.compvar-eval-word "$subword" noglob + if [[ $isfirst ]]; then + isfirst= + local iword=${#words[@]}; ((iword&&iword--)) + words[iword]=${words[iword]}$ret + else + ble/array#push words "$ret" + fi + done + fi + return 0 +} +function ble/complete/progcomp/.compvar-generate-subwords/impl2 { + local word=$1 + ble/syntax:bash/simple-word/reconstruct-incomplete-word "$word" || return 1 + ble/complete/progcomp/.compvar-eval-word "$ret"; (($?==148)) && return 148; local value1=$ret + if [[ $point ]]; then + if ((point==${#word})); then + point=${#value1} + elif ble/syntax:bash/simple-word/reconstruct-incomplete-word "${word::point}"; then + ble/complete/progcomp/.compvar-eval-word "$ret"; (($?==148)) && return 148 + point=${#ret} + fi + fi + ble/complete/progcomp/.compvar-perform-wordbreaks "$value1"; words=("${ret[@]}") + return 0 +} +function ble/complete/progcomp/.compvar-generate-subwords { + local word1=$1 ret simple_flags simple_ibrace + if [[ ! $word1 ]]; then + subword_flags=E + words=('') + elif [[ $word1 == '~' ]]; then + subword_flags=Q + words=('~') + elif ble/complete/progcomp/.compvar-generate-subwords/impl1 "$word1"; then + subword_flags=E + elif ble/complete/progcomp/.compvar-generate-subwords/impl2 "$word1"; then + subword_flags=E + else + ble/complete/progcomp/.compvar-perform-wordbreaks "$word1"; words=("${ret[@]}") + fi +} +function ble/complete/progcomp/.compvar-quote-subword { + local word=$1 to_quote= is_evaluated= is_quoted= + if [[ $subword_flags == *[EQ]* ]]; then + [[ $subword_flags == *E* ]] && to_quote=1 + elif ble/syntax:bash/simple-word/reconstruct-incomplete-word "$word"; then + is_evaluated=1 + ble/complete/progcomp/.compvar-eval-word "$ret"; (($?==148)) && return 148; word=$ret + to_quote=1 + fi + if [[ $to_quote ]]; then + local shell_specialchars=']\ ["'\''`$|&;<>()*?{}!^'$'\n\t' q="'" Q="'\''" qq="''" + if ((index>0)) && [[ $word == *["$shell_specialchars"]* || $word == [#~]* ]]; then + is_quoted=1 + word="'${w//$q/$Q}'" word=${word#"$qq"} word=${word%"$qq"} + fi + fi + if [[ $p && $word != "$1" ]]; then + if ((p==${#1})); then + p=${#word} + else + local left=${word::p} + if [[ $is_evaluated ]]; then + if ble/syntax:bash/simple-word/reconstruct-incomplete-word "$left"; then + ble/complete/progcomp/.compvar-eval-word "$ret"; (($?==148)) && return 148; left=$ret + fi + fi + if [[ $is_quoted ]]; then + left="'${left//$q/$Q}" left=${left#"$qq"} + fi + p=${#left} + fi + fi + ret=$word +} +function ble/complete/progcomp/.compvar-initialize { + COMP_TYPE=9 + COMP_KEY=9 + ((${#KEYS[@]})) && COMP_KEY=${KEYS[${#KEYS[@]}-1]:-9} # KEYS defined in ble-decode/widget/.call-keyseq + local wordbreaks + ble/complete/progcomp/.compvar-initialize-wordbreaks + progcomp_prefix= + COMP_CWORD= + COMP_POINT= + COMP_LINE= + COMP_WORDS=() + local ret simple_flags simple_ibrace + local word1 index=0 offset=0 sep= + for word1 in "${comp_words[@]}"; do + local point=$((comp_point-offset)) + ((0<=point&&point<=${#word1})) || point= + ((offset+=${#word1})) + local words subword_flags= + ble/complete/progcomp/.compvar-generate-subwords "$word1" + local w wq i=0 o=0 p + for w in "${words[@]}"; do + p= + if [[ $point ]]; then + ((p=point-o)) + ((i%2==0?p<=${#w}:p<${#w})) || p= + ((o+=${#w},i++)) + fi + [[ $p ]] && point= + [[ $point ]] && progcomp_prefix=$progcomp_prefix$w + ble/complete/progcomp/.compvar-quote-subword "$w"; local wq=$ret + if [[ $p ]]; then + COMP_CWORD=${#COMP_WORDS[*]} + ((COMP_POINT=${#COMP_LINE}+${#sep}+p)) + fi + ble/array#push COMP_WORDS "$wq" + COMP_LINE=$COMP_LINE$sep$wq + sep= + done + sep=' ' + ((offset++)) + ((index++)) + done +} +function ble/complete/progcomp/.compgen-helper-prog { + if [[ $comp_prog ]]; then + local COMP_WORDS COMP_CWORD + local -x COMP_LINE COMP_POINT COMP_TYPE COMP_KEY + ble/complete/progcomp/.compvar-initialize + local cmd=${COMP_WORDS[0]} cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} + if [[ $comp_opts == *:ble/prog-trim:* ]]; then + local compreply + ble/util/assign compreply '"$comp_prog" "$cmd" "$cur" "$prev" < /dev/null' + ble/bin/sed "s/[[:space:]]\{1,\}\$//" <<< "$compreply" + else + "$comp_prog" "$cmd" "$cur" "$prev" < /dev/null + fi + fi +} +function ble/complete/progcomp/compopt { + local ext=0 + local -a ospec + while (($#)); do + local arg=$1; shift + case "$arg" in + (-*) + local ic c + for ((ic=1;ic<${#arg};ic++)); do + c=${arg:ic:1} + case "$c" in + (o) ospec[${#ospec[@]}]="-$1"; shift ;; + ([DE]) fDefault=1; break 2 ;; + (*) ((ext==0&&(ext=1))) ;; + esac + done ;; + (+o) ospec[${#ospec[@]}]="+$1"; shift ;; + (*) + return "$ext" ;; + esac + done + local s + for s in "${ospec[@]}"; do + case "$s" in + (-*) comp_opts=${comp_opts//:"${s:1}":/:}${s:1}: ;; + (+*) comp_opts=${comp_opts//:"${s:1}":/:} ;; + esac + done + return "$ext" +} +function ble/complete/progcomp/.check-limits { + ((cand_iloop++%bleopt_complete_polling_cycle==0)) && + [[ ! -t 0 ]] && ble/complete/check-cancel <&$_ble_util_fd_stdin && + return 148 + ble/complete/source/test-limit $((progcomp_read_count++)) + return "$?" +} +function ble/complete/progcomp/.compgen-helper-func { + [[ $comp_func ]] || return 1 + local -a COMP_WORDS + local COMP_LINE COMP_POINT COMP_CWORD COMP_TYPE COMP_KEY + ble/complete/progcomp/.compvar-initialize + local progcomp_read_count=0 + local _ble_builtin_read_hook='ble/complete/progcomp/.check-limits || { builtin read "$@" < /dev/null; return 148; }' + local fDefault= + local cmd=${COMP_WORDS[0]} cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} + ble/function#push compopt 'ble/complete/progcomp/compopt "$@"' + ble/function#push ssh ' + local IFS=$_ble_term_IFS + if [[ " ${FUNCNAME[*]} " == *" ble/complete/progcomp/.compgen "* ]]; then + local -a args; args=("$@") + ble/util/conditional-sync "exec ssh \"\${args[@]}\"" \ + "! ble/complete/check-cancel <&$_ble_util_fd_stdin" 128 progressive-weight:killall + else + ble/function#push/call-top "$@" + fi' + builtin eval '"$comp_func" "$cmd" "$cur" "$prev"' < /dev/null >&$_ble_util_fd_stdout 2>&$_ble_util_fd_stderr; local ret=$? + ble/function#pop ssh + ble/function#pop compopt + [[ $ret == 124 ]] && progcomp_retry=1 + return 0 +} +function ble/complete/progcomp/.parse-complete/next { + if [[ $compdef =~ $rex ]]; then + builtin eval "arg=$BASH_REMATCH" + compdef=${compdef:${#BASH_REMATCH}} + return 0 + elif [[ ${compdef%%' '*} ]]; then + arg=${compdef%%' '*} + compdef=${compdef#*' '} + return 0 + else + return 1 + fi +} +function ble/complete/progcomp/.parse-complete/optarg { + optarg= + if ((ic+1<${#arg})); then + optarg=${arg:ic+1} + ic=${#arg} + return 0 + elif [[ $compdef =~ $rex ]]; then + builtin eval "optarg=$BASH_REMATCH" + compdef=${compdef:${#BASH_REMATCH}} + return 0 + else + return 2 + fi +} +function ble/complete/progcomp/.parse-complete { + compoptions=() + comp_prog= + comp_func= + flag_noquote= + local compdef=${1#'complete '} + local arg optarg rex='^([^][*?;&|[:space:]<>()\`$"'\''{}#^!]|\\.|'\''[^'\'']*'\'')+[[:space:]]+' # #D1709 safe (WA gawk 4.0.2) + while ble/complete/progcomp/.parse-complete/next; do + case $arg in + (-*) + local ic c + for ((ic=1;ic<${#arg};ic++)); do + c=${arg:ic:1} + case "$c" in + ([abcdefgjksuvE]) + case $c in + (c) flag_noquote=1 ;; + (d) ((_ble_bash>=40300)) && flag_noquote=1 ;; + (f) ((40000<=_ble_bash&&_ble_bash<40200)) && flag_noquote=1 ;; + esac + ble/array#push compoptions "-$c" ;; + ([pr]) + ;; # 無視 (-p 表示 -r 削除) + ([AGWXPS]) + ble/complete/progcomp/.parse-complete/optarg || break 2 + if [[ $c == A ]]; then + case $optarg in + (command) flag_noquote=1 ;; + (directory) ((_ble_bash>=40300)) && flag_noquote=1 ;; + (file) ((40000<=_ble_bash&&_ble_bash<40200)) && flag_noquote=1 ;; + esac + fi + ble/array#push compoptions "-$c" "$optarg" ;; + (o) + ble/complete/progcomp/.parse-complete/optarg || break 2 + comp_opts=${comp_opts//:"$optarg":/:}$optarg: + ble/array#push compoptions "-$c" "$optarg" ;; + (C) + if ((_ble_bash<40000)); then + comp_prog=${compdef%' '} + compdef= + else + ble/complete/progcomp/.parse-complete/optarg || break 2 + comp_prog=$optarg + fi + ble/array#push compoptions "-$c" ble/complete/progcomp/.compgen-helper-prog ;; + (F) + if ((_ble_bash<40000)) && [[ $compdef == *' -C '* ]]; then + comp_prog=${compdef#*' -C '} + comp_prog=${comp_prog%' '} + ble/array#push compoptions '-C' ble/complete/progcomp/.compgen-helper-prog + comp_func=${compdef%%' -C '*} + else + comp_func=${compdef%' '} + fi + compdef= + ble/array#push compoptions "-$c" ble/complete/progcomp/.compgen-helper-func ;; + (*) + esac + done ;; + (*) + ;; # 無視 + esac + done +} +function ble/complete/progcomp/.filter-and-split-compgen { + flag_mandb= + local sed_script= + { + if [[ $comp_opts == *:ble/filter-by-prefix:* ]]; then + local ret; ble/string#escape-for-sed-regex "$COMPV"; local rex_compv=$ret + sed_script='!/^'$rex_compv'/d' + fi + [[ $use_workaround_for_git ]] && + sed_script=${sed_script:+$sed_script;}'s/[[:space:]]\{1,\}$//' + } + local out= + [[ $sed_script ]] && ble/util/assign out 'ble/bin/sed "$sed_script;/^\$/d" <<< "$compgen"' + [[ $out ]] || out=$compgen + local require_awk= + if [[ $comp_opts != *:nosort:* ]]; then + ble/util/assign out 'ble/bin/sort -u <<< "$out"' + else + require_awk=1 # for uniq + fi + local -a args_mandb=() + if [[ $compcmd == "${comp_words[0]}" && $COMPV != [!-]* ]]; then + if local ret; ble/complete/mandb/generate-cache "$compcmd"; then + require_awk=1 + args_mandb=(mode=mandb "$ret") + fi + fi + if [[ $require_awk ]]; then + local awk_script=' + BEGIN { mandb_count = 0; } + mode == "mandb" { + name = $0 + sub(/'"$_ble_term_FS"'.*/, "", name); + if (!mandb[name]) mandb[name] = $0; + next; + } + !hash[$0]++ { + if (/^$/) next; + name = $0 + sub(/=$/, "", name); + if (mandb[name]) { + mandb_count++; + print mandb[name]; + next; + } else if (sub(/^--no-/, "--", name)) { + if ((entry = mandb[name]) || (entry = mandb[substr(name, 2)])) { + split(entry, record, FS); + if ((desc = record[4])) { + desc = "\033[1mReverse[\033[m " desc " \033[;1m]\033[m"; + if (match($0, /[[:space:]]*[:=[]/)) { + option = substr($0, 1, RSTART - 1); + optarg = substr($0, RSTART); + suffix = substr($0, RSTART, 1); + if (suffix == "[") suffix = ""; + } else { + option = $0; + optarg = ""; + suffix = " "; + } + mandb_count++; + print option FS optarg FS suffix FS desc; + } + next; + } + } + print $0; + } + END { if (mandb_count) exit 10; } + ' + ble/util/assign-array "$1" 'ble/bin/awk -F "$_ble_term_FS" "$awk_script" "${args_mandb[@]}" mode=compgen - <<< "$out"' + (($?==10)) && flag_mandb=1 + else + ble/string#split-lines "$1" "$out" + fi + return 0 +} 2>/dev/null +function ble/complete/progcomp/.cobraV2.patch { + local prefix=$cur + [[ $comps_flags == *v* ]] && prefix=$COMPV + local unprocessed has_desc= + unprocessed=() + local lines line cand desc + for lines in "${out[@]}"; do + ble/string#split-lines lines "$lines" + for line in "${lines[@]}"; do + if [[ $line == *$'\t'* ]]; then + cand=${line%%$'\t'*} + desc=${line#*$'\t'} + [[ $cand == "$prefix"* ]] || continue + ble/complete/cand/yield word "$cand" "$desc" + has_desc=1 + else + ble/array#push unprocessed "$line" + fi + done + done + [[ $has_desc ]] && bleopt complete_menu_style=desc + if ((${#unprocessed[@]})); then + out=("${unprocessed[@]}") + ble/function#advice/do + fi +} +function ble/complete/progcomp/.compgen { + local opts=$1 + local compcmd= is_special_completion= + local -a alias_args=() + if [[ :$opts: == *:initial:* ]]; then + if ((_ble_bash>=50000)); then + is_special_completion=1 + compcmd='-I' + else + compcmd=_InitialWorD_ + fi + elif [[ :$opts: == *:default:* ]]; then + if ((_ble_bash>=40100)); then + builtin complete -p -D &>/dev/null || return 1 + is_special_completion=1 + compcmd='-D' + else + builtin complete -p _DefaultCmD_ &>/dev/null || return 1 + compcmd=_DefaultCmD_ + fi + else + compcmd=${comp_words[0]} + fi + local compdef + if [[ $is_special_completion ]]; then + ble/util/assign compdef 'builtin complete -p "$compcmd" 2>/dev/null' + elif ble/syntax:bash/simple-word/is-simple "$compcmd"; then + ble/util/assign compdef "builtin complete -p -- $compcmd 2>/dev/null" + local ret; ble/syntax:bash/simple-word/eval "$compcmd"; compcmd=$ret + else + ble/util/assign compdef 'builtin complete -p -- "$compcmd" 2>/dev/null' + fi + compdef=${compdef%"${compcmd:-''}"} + compdef=${compdef%' '}' ' + local comp_prog comp_func compoptions flag_noquote + ble/complete/progcomp/.parse-complete "$compdef" + if [[ $comp_func ]]; then + [[ $comp_func == _fzf_* ]] && + ble-import -f contrib/fzf-completion + if ble/is-function _quote_readline_by_ref; then + function _quote_readline_by_ref { + if [[ $1 == \'* ]]; then + printf -v "$2" %s "${1:1}" + else + printf -v "$2" %q "$1" + [[ ${!2} == \$* ]] && builtin eval "$2=${!2}" + fi + } + ble/function#suppress-stderr _filedir 2>/dev/null + ble/function#suppress-stderr _find 2>/dev/null + ble/function#suppress-stderr _scp_remote_files 2>/dev/null + ble/complete/mandb:_parse_help/inject + fi + if [[ $comp_func == __start_* ]]; then + local target=__${comp_func#__start_}_handle_completion_types + ble/is-function "$target" && + ble/function#advice around "$target" ble/complete/progcomp/.cobraV2.patch + fi + ble/function#advice around _dnf_commands_helper ' + ble/util/conditional-sync \ + ble/function#advice/do \ + "! ble/complete/check-cancel <&$_ble_util_fd_stdin" 128 progressive-weight:killall' 2>/dev/null + fi + if [[ $comp_prog ]]; then + if [[ $comp_prog == aws_completer ]]; then + comp_opts=${comp_opts}ble/no-mark-directories:ble/prog-trim: + fi + fi + ble/complete/check-cancel && return 148 + local compgen compgen_compv=$COMPV + if [[ ! $flag_noquote && :$comp_opts: != *:noquote:* ]]; then + local q="'" Q="'\''" + compgen_compv="'${compgen_compv//$q/$Q}'" + fi + local progcomp_prefix= progcomp_retry= + IFS=$IFS word= ble/util/assign compgen 'builtin compgen "${compoptions[@]}" -- "$compgen_compv" 2>/dev/null' + if [[ $progcomp_retry && ! $_ble_complete_retry_guard ]]; then + local _ble_complete_retry_guard=1 + opts=:$opts: + opts=${opts//:default:/:} + ble/complete/progcomp/.compgen "$opts" + return "$?" + fi + [[ $compgen ]] || return 1 + local use_workaround_for_git= + if [[ $comp_func == __git* && $comp_opts == *:nospace:* ]]; then + use_workaround_for_git=1 + comp_opts=${comp_opts//:nospace:/:} + fi + local cands flag_mandb= + ble/complete/progcomp/.filter-and-split-compgen cands # compgen (comp_opts, etc) -> cands, flag_mandb + ble/complete/source/test-limit ${#cands[@]} || return 1 + [[ $comp_opts == *:filenames:* && $COMPV == */* ]] && COMP_PREFIX=${COMPV%/*}/ + local old_cand_count=$cand_count + local action=progcomp "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe + ble/complete/cand/yield.initialize "$action" + if [[ $flag_mandb ]]; then + local -a entries; entries=("${cands[@]}") + cands=() + local fs=$_ble_term_FS has_desc= icand=0 entry + for entry in "${entries[@]}"; do + ((cand_iloop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148 + if [[ $entry == -*"$fs"*"$fs"*"$fs"* ]]; then + local cand=${entry%%"$fs"*} + ble/complete/cand/yield mandb "$cand" "$entry" + [[ $entry == *"$fs"*"$fs"*"$fs"?* ]] && has_desc=1 + else + cands[icand++]=$progcomp_prefix$entry + fi + done + [[ $has_desc ]] && bleopt complete_menu_style=desc + else + [[ $progcomp_prefix ]] && + if ((_ble_bash>=40300)) && ! shopt -q compat42; then + cands=("${cands[@]/#/"$progcomp_prefix"}") # WA #D1570 #D1751 safe + else + cands=("${cands[@]/#/$progcomp_prefix}") # WA #D1570 #D1738 safe + fi + fi + ble/complete/cand/yield.batch "$action" "$comp_opts" + [[ $comp_opts == *:plusdirs:* ]] && ble/complete/source:dir + ((cand_count>old_cand_count)) +} +function ble/complete/progcomp/.compline-rewrite-command { + local ocmd=${comp_words[0]} + [[ $1 != "$ocmd" ]] || (($#>=2)) || return 1 + local IFS=$_ble_term_IFS + local ins="$*" + if (($#==0)); then + local ret; ble/string#ltrim "${comp_line:${#ocmd}}" + ((comp_point-=${#comp_line}-${#ret})) + comp_line=$ret + else + comp_line=$ins${comp_line:${#ocmd}} + ((comp_point-=${#ocmd})) + fi + ((comp_point<0&&(comp_point=0),comp_point+=${#ins})) + comp_words=("$@" "${comp_words[@]:1}") + ((comp_cword&&(comp_cword+=$#-1))) +} +function ble/complete/progcomp/.split-alias-words { + local tail=$1 + local rex_redir='^'$_ble_syntax_bash_RexRedirect + local rex_word='^'$_ble_syntax_bash_simple_rex_element'+' + local rex_delim=$'^[\n;|&]' + local rex_spaces=$'^[ \t]+' + local rex_misc='^[<>()]+' + local -a words=() + while [[ $tail ]]; do + if [[ $tail =~ $rex_redir && $tail != ['<>']'('* ]]; then + ble/array#push words "$BASH_REMATCH" + tail=${tail:${#BASH_REMATCH}} + elif [[ $tail =~ $rex_word ]]; then + local w=$BASH_REMATCH + tail=${tail:${#w}} + if [[ $tail && $tail != ["$_ble_term_IFS;|&<>()"]* ]]; then + local s=${tail%%["$_ble_term_IFS"]*} + tail=${tail:${#s}} + w=$w$s + fi + ble/array#push words "$w" + elif [[ $tail =~ $rex_delim ]]; then + words=() + tail=${tail:${#BASH_REMATCH}} + elif [[ $tail =~ $rex_spaces ]]; then + tail=${tail:${#BASH_REMATCH}} + elif [[ $tail =~ $rex_misc ]]; then + ble/array#push words "$BASH_REMATCH" + tail=${tail:${#BASH_REMATCH}} + else + local w=${tail%%["$_ble_term_IFS"]*} + ble/array#push words "$w" + tail=${tail:${#w}} + fi + done + local i=0 rex_assign='^[a-zA-Z_0-9]+(\['$_ble_syntax_bash_simple_rex_element'*\])?\+?=' + while ((i<${#words[@]})); do + if [[ ${words[i]} =~ $rex_assign ]]; then + ((i++)) + elif [[ ${words[i]} =~ $rex_redir && ${words[i]} != ['<>']'('* ]]; then + ((i+=2)) + else + break + fi + done + ret=("${words[@]:i}") +} +function ble/complete/progcomp { + local cmd=${1-${comp_words[0]}} opts=$2 + local -a orig_comp_words; orig_comp_words=("${comp_words[@]}") + local comp_words comp_line=$comp_line comp_point=$comp_point comp_cword=$comp_cword + comp_words=("$cmd" "${orig_comp_words[@]:1}") + local orig_qcmds_set= + local -a orig_qcmds=() + local -a alias_args=() + [[ :$opts: == *:__recursive__:* ]] || + local alias_checked=' ' + while :; do + local ret ucmd qcmds + ucmd=$cmd qcmds=("$cmd") + if ble/syntax:bash/simple-word/is-simple "$cmd"; then + if ble/syntax:bash/simple-word/eval "$cmd" noglob && + [[ $ret != "$cmd" || ${#ret[@]} -ne 1 ]]; then + ucmd=${ret[0]} qcmds=() + local word + for word in "${ret[@]}"; do + ble/string#quote-word "$word" quote-empty + ble/array#push qcmds "$ret" + done + else + ble/string#quote-word "$cmd" quote-empty + qcmds=("$ret") + fi + [[ $cmd == "${orig_comp_words[0]}" ]] && + orig_qcmds_set=1 orig_qcmds=("${qcmds[@]}") + fi + if ble/is-function "ble/cmdinfo/complete:$ucmd"; then + ble/complete/progcomp/.compline-rewrite-command "${qcmds[@]}" "${alias_args[@]}" + "ble/cmdinfo/complete:$ucmd" "$opts" + return "$?" + elif [[ $ucmd == */?* ]] && ble/is-function "ble/cmdinfo/complete:${ucmd##*/}"; then + ble/string#quote-word "${ucmd##*/}"; qcmds[0]=$ret + ble/complete/progcomp/.compline-rewrite-command "${qcmds[@]}" "${alias_args[@]}" + "ble/cmdinfo/complete:${ucmd##*/}" "$opts" + return "$?" + elif builtin complete -p -- "$ucmd" &>/dev/null; then + ble/complete/progcomp/.compline-rewrite-command "${qcmds[@]}" "${alias_args[@]}" + ble/complete/progcomp/.compgen "$opts" + return "$?" + elif [[ $ucmd == */?* ]] && builtin complete -p -- "${ucmd##*/}" &>/dev/null; then + ble/string#quote-word "${ucmd##*/}"; qcmds[0]=$ret + ble/complete/progcomp/.compline-rewrite-command "${qcmds[@]}" "${alias_args[@]}" + ble/complete/progcomp/.compgen "$opts" + return "$?" + elif + ble/function#try __load_completion "${ucmd##*/}" &>/dev/null && + builtin complete -p -- "${ucmd##*/}" &>/dev/null + then + ble/string#quote-word "${ucmd##*/}"; qcmds[0]=$ret + ble/complete/progcomp/.compline-rewrite-command "${qcmds[@]}" "${alias_args[@]}" + ble/complete/progcomp/.compgen "$opts" + return "$?" + fi + alias_checked=$alias_checked$cmd' ' + ((_ble_bash<50000)) || shopt -q progcomp_alias || break + local ret + ble/alias#expand "$cmd" + [[ $ret == "$cmd" ]] && break + ble/complete/progcomp/.split-alias-words "$ret" + if ((${#ret[@]}==0)); then + ble/complete/progcomp/.compline-rewrite-command "${alias_args[@]}" + if ((${#comp_words[@]})); then + if ((comp_cword==0)); then + ble/complete/source:command + else + ble/complete/progcomp "${comp_words[0]}" "__recursive__:$opts" + fi + fi + return $? + fi + [[ $alias_checked != *" $ret "* ]] || break + cmd=$ret + ((${#ret[@]}>=2)) && + alias_args=("${ret[@]:1}" "${alias_args[@]}") + done + comp_words=("${orig_comp_words[@]}") + [[ $orig_qcmds_set ]] && + ble/complete/progcomp/.compline-rewrite-command "${orig_qcmds[@]}" + ble/complete/progcomp/.compgen "default:$opts" +} +_ble_complete_option_chars='_!#$%&:;.,^~|\\?\/*a-zA-Z0-9' +function ble/complete/action:mandb/initialize { + ble/complete/action/quote-insert +} +function ble/complete/action:mandb/initialize.batch { + ble/complete/action/quote-insert.batch newline +} +function ble/complete/action:mandb/complete { + ble/complete/action/complete.close-quotation + local fields + ble/string#split fields "$_ble_term_FS" "$DATA" + local tail=${fields[2]} + [[ $tail == ' ' && $comps_flags == *x* ]] && tail=',' + ble/complete/action/complete.addtail "$tail" +} +function ble/complete/action:mandb/init-menu-item { + local ret; ble/color/face2g argument_option; g=$ret + local fields + ble/string#split fields "$_ble_term_FS" "$DATA" + suffix=${fields[1]} +} +function ble/complete/action:mandb/get-desc { + local fields + ble/string#split fields "$_ble_term_FS" "$DATA" + desc=${fields[3]} +} +function ble/complete/mandb/load-mandb-conf { + [[ -s $1 ]] || return 0 + local line words + while builtin read "${_ble_bash_tmout_wa[@]}" -r line || [[ $line ]]; do + ble/string#split-words words "${line%%'#'*}" + case ${words[0]} in + (MANDATORY_MANPATH) + [[ -d ${words[1]} ]] && + ble/array#push manpath_mandatory "${words[1]}" ;; + (MANPATH_MAP) + ble/dict#set manpath_map "${words[1]}" "${words[2]}" ;; + esac + done < "$1" +} +_ble_complete_mandb_default_manpath=() +function ble/complete/mandb/initialize-manpath { + ((${#_ble_complete_mandb_default_manpath[@]})) && return 0 + local manpath + MANPATH= ble/util/assign manpath 'manpath || ble/bin/man -w' 2>/dev/null + ble/string#split manpath : "$manpath" + if ((${#manpath[@]}==0)); then + local -a manpath_mandatory=() + builtin eval -- "${_ble_util_dict_declare//NAME/manpath_map}" + ble/complete/mandb/load-mandb-conf /etc/man_db.conf + ble/complete/mandb/load-mandb-conf ~/.manpath + if ((${#manpath_mandatory[@]}==0)); then + local ret + ble/complete/util/eval-pathname-expansion '~/*/share/man' + ble/array#push manpath_mandatory "${ret[@]}" + ble/complete/util/eval-pathname-expansion '~/@(opt|.opt)/*/share/man' + ble/array#push manpath_mandatory "${ret[@]}" + for ret in /usr/local/share/man /usr/local/man /usr/share/man; do + [[ -d $ret ]] && ble/array#push manpath_mandatory "$ret" + done + fi + builtin eval -- "${_ble_util_dict_declare//NAME/mark}" + local paths path ret + ble/string#split paths : "$PATH" + for path in "${paths[@]}"; do + [[ -d $path ]] || continue + [[ $path == *?/ ]] && path=${path%/} + if ble/dict#get manpath_map "$path"; then + path=$ret + else + path=${path%/bin}/share/man + fi + if [[ -d $path ]] && ! ble/set#contains mark "$path"; then + ble/set#add mark "$path" + ble/array#push manpath "$path" + fi + done + for path in "${manpath_mandatory[@]}"; do + if [[ -d $path ]] && ! ble/set#contains mark "$path"; then + ble/set#add mark "$path" + ble/array#push manpath "$path" + fi + done + fi + _ble_complete_mandb_default_manpath=("${manpath[@]}") +} +function ble/complete/mandb/search-file/.extract-path { + local command=$1 + [[ $_ble_complete_mandb_lang ]] && + local LC_ALL=$$_ble_complete_mandb_lang + ble/util/assign path 'ble/bin/man -w "$command"' 2>/dev/null +} +ble/function#suppress-stderr ble/complete/mandb/search-file/.extract-path +function ble/complete/mandb/search-file/.check { + local path=$1 + if [[ $path && -s $path ]]; then + ret=$path + return 0 + else + return 1 + fi +} +function ble/complete/mandb/search-file { + local command=$1 + local path + ble/complete/mandb/search-file/.extract-path "$command" + ble/complete/mandb/search-file/.check "$path" && return + ble/string#split ret : "$MANPATH" + ((${#ret[@]})) || ret=('') + local -a manpath=() + for path in "${ret[@]}"; do + if [[ $path ]]; then + ble/array#push manpath "$path" + else + ble/complete/mandb/initialize-manpath + ble/array#push manpath "${_ble_complete_mandb_default_manpath[@]}" + fi + done + local path + for path in "${manpath[@]}"; do + [[ -d $path ]] || continue + ble/complete/mandb/search-file/.check "$path/man1/$command.1" && return 0 + ble/complete/mandb/search-file/.check "$path/man1/$command.8" && return 0 + if ble/is-function ble/bin/gzip; then + ble/complete/mandb/search-file/.check "$path/man1/$command.1.gz" && return 0 + ble/complete/mandb/search-file/.check "$path/man1/$command.8.gz" && return 0 + fi + if ble/is-function ble/bin/bzcat; then + ble/complete/mandb/search-file/.check "$path/man1/$command.1.bz" && return 0 + ble/complete/mandb/search-file/.check "$path/man1/$command.1.bz2" && return 0 + ble/complete/mandb/search-file/.check "$path/man1/$command.8.bz" && return 0 + ble/complete/mandb/search-file/.check "$path/man1/$command.8.bz2" && return 0 + fi + if ble/is-function ble/bin/xzcat; then + ble/complete/mandb/search-file/.check "$path/man1/$command.1.xz" && return 0 + ble/complete/mandb/search-file/.check "$path/man1/$command.8.xz" && return 0 + fi + if ble/is-function ble/bin/lzcat; then + ble/complete/mandb/search-file/.check "$path/man1/$command.1.lzma" && return 0 + ble/complete/mandb/search-file/.check "$path/man1/$command.8.lzma" && return 0 + fi + done + return 1 +} +if ble/bin/.freeze-utility-path preconv; then + function ble/complete/mandb/.preconv { ble/bin/preconv; } +else + function ble/complete/mandb/.preconv { + ble/bin/od -A n -t u1 -v | ble/bin/awk ' + BEGIN { + ECHAR = 65533; # U+FFFD + byte = 0; + for (i = 0; byte < 128; byte++) { mtable[byte] = 0; vtable[byte] = i++; } + for (i = 0; byte < 192; byte++) { mtable[byte] = 0; vtable[byte] = ECHAR; } + for (i = 0; byte < 224; byte++) { mtable[byte] = 1; vtable[byte] = i++; } + for (i = 0; byte < 240; byte++) { mtable[byte] = 2; vtable[byte] = i++; } + for (i = 0; byte < 248; byte++) { mtable[byte] = 3; vtable[byte] = i++; } + for (i = 0; byte < 252; byte++) { mtable[byte] = 4; vtable[byte] = i++; } + for (i = 0; byte < 254; byte++) { mtable[byte] = 5; vtable[byte] = i++; } + for (i = 0; byte < 256; byte++) { mtable[byte] = 0; vtable[byte] = ECHAR; } + M = 0; C = 0; + } + function put_uchar(uchar) { + if (uchar < 128) + printf("%c", uchar); + else + printf("\\[u%04X]", uchar); + } + function process_byte(byte) { + if (M) { + if (128 <= byte && byte < 192) { + C = C * 64 + byte % 64; + if (--M == 0) put_uchar(C); + return; + } else { + put_uchar(ECHAR); + M = 0; + } + } + M = mtable[byte]; + C = vtable[byte]; + if (M == 0) put_uchar(C); + } + { for (i = 1; i <= NF; i++) process_byte($i); } + ' + } +fi +_ble_complete_mandb_lang= +if ble/is-function ble/bin/groff; then + _ble_complete_mandb_convert_type=man + function ble/complete/mandb/convert-mandoc { + if [[ $_ble_util_locale_encoding == UTF-8 ]]; then + ble/bin/groff -k -Tutf8 -man + else + ble/bin/groff -Tascii -man + fi + } + if [[ $OSTYPE == darwin* ]] && ! ble/bin/groff -k -Tutf8 -man &>/dev/null <<< 'α'; then + if ble/bin/groff -T utf8 -m man &>/dev/null <<< '\[u03B1]'; then + function ble/complete/mandb/convert-mandoc { + if [[ $_ble_util_locale_encoding == UTF-8 ]]; then + ble/complete/mandb/.preconv | ble/bin/groff -T utf8 -m man + else + ble/bin/groff -T ascii -m man + fi + } + else + _ble_complete_mandb_lang=C + function ble/complete/mandb/convert-mandoc { + ble/bin/groff -T ascii -m man + } + fi + fi +elif ble/is-function ble/bin/nroff; then + _ble_complete_mandb_convert_type=man + function ble/complete/mandb/convert-mandoc { + if [[ $_ble_util_locale_encoding == UTF-8 ]]; then + ble/bin/nroff -Tutf8 -man + else + ble/bin/groff -Tascii -man + fi + } +elif ble/is-function ble/bin/mandoc; then + _ble_complete_mandb_convert_type=mdoc + function ble/complete/mandb/convert-mandoc { + ble/bin/mandoc -mdoc + } +fi +function ble/complete/mandb/.generate-cache-from-man { + ble/is-function ble/bin/man && + ble/is-function ble/complete/mandb/convert-mandoc || return 1 + local command=$1 + local ret + ble/complete/mandb/search-file "$command" || return 1 + local path=$ret + case $ret in + (*.gz) ble/bin/gzip -cd "$path" ;; + (*.bz|*.bz2) ble/bin/bzcat "$path" ;; + (*.lzma) ble/bin/lzcat "$path" ;; + (*.xz) ble/bin/xzcat "$path" ;; + (*) ble/bin/cat "$path" ;; + esac | ble/bin/awk -v type="$_ble_complete_mandb_convert_type" ' + BEGIN { + g_keys_count = 0; + g_desc = ""; + if (type == "man") { + print ".TH __ble_ignore__ 1 __ble_ignore__ __ble_ignore__"; + print ".ll 9999" + topic_start = ".TP"; + } + mode = "begin"; + fmt3_state = ""; + fmt5_state = ""; + fmt6_state = ""; + } + function output_pair(key, desc) { + print ""; + print "__ble_key__"; + if (topic_start != "") print topic_start; + print key; + print ""; + print "__ble_desc__"; + print ""; + print desc; + } + function flush_topic(_, i) { + if (g_keys_count != 0) { + for (i = 0; i < g_keys_count; i++) + output_pair(g_keys[i], g_desc); + } + g_keys_count = 0; + g_desc = ""; + fmt3_flush(); + fmt5_state = ""; + fmt6_flush(); + } + mode == "begin" && /^\.(Dd|Nm)[[:space:]]/ { + if (type == "man" && /^\.Dd[[:space:]]+\$Mdoc/) topic_start = ""; + print $0; + } + function register_key(key) { + g_keys[g_keys_count++] = key; + g_desc = ""; + } + /^\.ig/ { mode = "ignore"; next; } + mode == "ignore" { + if (/^\.\.[[:space:]]*/) mode = "none"; + next; + } + { + sub(/[[:space:]]+$/, ""); + REQ = match($0, /^\.[_[:alnum:]]+/) ? substr($0, 2, RLENGTH - 1) : ""; + } + REQ ~ /^(S[Ss]|S[Hh]|Pp)$/ { flush_topic(); next; } + REQ == "PP" { + flush_topic(); + fmt5_state = "key"; + fmt5_key = ""; + fmt5_desc = ""; + next; + } + fmt5_state { + if (fmt5_state == "key") { + if (/^\.RS([^_[:alnum:]]|$)/) + fmt5_state = "desc"; + else if (/^\.RE([^_[:alnum:]]|$)/) + fmt5_state = "none"; + else + fmt5_key = (fmt5_key ? "\n" : "") $0; + } else if (fmt5_state == "desc") { + if (/^\.RE([^_[:alnum:]]|$)/) { + register_key(fmt5_key); + g_desc = fmt5_desc; + flush_topic(); + fmt5_state = ""; + } else + fmt5_desc = (fmt5_desc ? "\n" : "") $0; + } + } + REQ == "HP" { + flush_topic(); + fmt3_state = "key"; + fmt3_key_count = 0; + fmt3_desc = ""; + next; + } + function fmt3_process(_, key) { + if (REQ == "TP") { fmt3_flush(); return; } + if (REQ == "PD") return; + if (fmt3_state == "key") { + if (REQ == "IP") { fmt3_state = "desc"; return; } + if (match($0, /( | )[[:space:]]*/)) { + fmt3_keys[fmt3_key_count++] = substr($0, 1, RSTART - 1); + fmt3_desc = substr($0, RSTART + RLENGTH); + fmt3_state = "desc"; + } else { + fmt3_keys[fmt3_key_count++] = $0; + } + } else if (fmt3_state == "desc") { + if (fmt3_desc != "") fmt3_desc = fmt3_desc "\n"; + fmt3_desc = fmt3_desc $0; + } + } + function fmt3_flush(_, i) { + if (fmt3_state == "desc" && fmt3_key_count > 0) { + for (i = 0; i < fmt3_key_count; i++) + register_key(fmt3_keys[i]); + g_desc = fmt3_desc; + } + fmt3_state = ""; + fmt3_key_count = 0; + fmt3_desc = ""; + } + fmt3_state { fmt3_process(); } + /^\.IP[[:space:]]+".*"([[:space:]]+[0-9]+)?$/ && fmt3_state != "key" { + fmt6_init(); + fmt4_init(); + next; + } + function fmt4_init() { + if (mode != "fmt4_desc") + if (!(g_keys_count && g_desc == "")) flush_topic(); + gsub(/^\.IP[[:space:]]+"|"([[:space:]]+[0-9]+)?$/, ""); + register_key($0); + mode = "fmt4_desc"; + } + mode == "fmt4_desc" { + if ($0 == "") { flush_topic(); mode = "none"; next; } + if (g_keys_count == 1 && g_keys[0] == "\\(bu" && match($0, /^\\fC[^\\]+\\fP( or \\fC[^\\]+\\fP)?/) > 0) { + _key = substr($0, 1, RLENGTH); + _desc = substr($0, RLENGTH + 1); + if (match(_key, / or \\fC[^\\]+\\fP/) > 0) + _key = substr(_key, 1, RSTART - 1) ", " substr(_key, RSTART + 4); + g_keys[0] = _key; + g_desc = _desc; + next; + } + if (REQ == "PD") next; + if (/^\.IX[[:space:]]+Item[[:space:]]+/) next; + if (g_desc != "") g_desc = g_desc "\n"; + g_desc = g_desc $0; + } + function fmt6_init() { + fmt6_flush(); + fmt6_state = "desc" + fmt6_key = $0; + fmt6_desc = ""; + } + fmt6_state { + if (REQ == "IX") { + fmt6_state = ""; + } else if (REQ == "IP") { + fmt6_flush(); + } else { + fmt6_desc = fmt6_desc $0 "\n"; + } + } + function fmt6_flush() { + if (!fmt6_state) return; + fmt6_state = ""; + if (fmt6_desc) + output_pair(fmt6_key, fmt6_desc); + } + /^\.It Fl([^_[:alnum:]]|$)/ { + if (g_keys_count && g_desc != "") flush_topic(); + sub(/^\.It Fl/, ".Fl"); + if ($0 ~ / Xo$/) { + g_current_key = $0; + mode = "fmt2_keyc" + } else { + register_key($0); + mode = "desc"; + } + next; + } + mode == "fmt2_keyc" { + if (/^\.PD[[:space:]]*([0-9]+[[:space:]]*)?$/) next; + g_current_key = g_current_key "\n" $0; + if (REQ == "Xc") { + register_key(g_current_key); + mode = "desc"; + } + next; + } + type == "man" && REQ == "TP" { + if (g_keys_count && g_desc != "") flush_topic(); + mode = "key1"; + next; + } + mode == "key1" { + if (/^\.PD[[:space:]]*([0-9]+[[:space:]]*)?$/) next; + register_key($0); + mode = "desc"; + next; + } + mode == "desc" { + if (REQ == "PD") next; + if (g_desc != "") g_desc = g_desc "\n"; + g_desc = g_desc $0; + } + END { flush_topic(); } + ' | ble/complete/mandb/convert-mandoc 2>/dev/null | ble/bin/awk -F "$_ble_term_FS" ' + function flush_pair(_, i) { + if (g_option_count) { + gsub(/\034/, "\x1b[7m^\\\x1b[27m", g_desc); + sub(/(\. |; ).*/, ".", g_desc); # Long descriptions are truncated. + for (i = 0; i < g_option_count; i++) + print g_options[i] FS g_desc; + } + g_option_count = 0; + g_desc = ""; + } + function process_key(line, _, n, specs, i, spec, option, optarg, suffix) { + gsub(/\x1b\[[ -?]*[@-~]/, "", line); # CSI seq + gsub(/\x1b[ -\/]*[0-~]/, "", line); # ESC seq + gsub(/.\x08/, "", line); # CHAR BS + gsub(/\x0E/, "", line); # SO + gsub(/\x0F/, "", line); # SI + gsub(/[\x00-\x1F]/, "", line); # Give up all the other control chars + gsub(/^[[:space:]]*|[[:space:]]*$/, "", line); + gsub(/[[:space:]]+/, " ", line); + if (line !~ /^[-+]./) return; + n = split(line, specs, /,([[:space:]]+|$)| or /); + prev_optarg = ""; + for (i = n; i > 0; i--) { + spec = specs[i]; + sub(/,[[:space:]]+$/, "", spec); + if (spec !~ /^[-+]/ || spec ~ /\034/) { specs[i] = ""; continue; } + if (match(spec, /\[[:=]?|[:=[:space:]]/)) { + option = substr(spec, 1, RSTART - 1); + optarg = substr(spec, RSTART); + suffix = substr(spec, RSTART + RLENGTH - 1, 1); + if (suffix == "[") suffix = ""; + prev_optarg = optarg; + } else { + option = spec; + optarg = ""; + suffix = " "; + if (prev_optarg ~ /[A-Z]|<.+>/) { + optarg = prev_optarg; + if (option ~ /^[-+].$/) { + sub(/^\[=/, "[", optarg); + sub(/^=/, "", optarg); + sub(/^[^[:space:][]/, " &", optarg); + } else { + if (optarg ~ /^\[[^:=]/) + sub(/^\[/, "[=", optarg); + else if (optarg ~ /^[^:=[:space:][]/) + optarg = " " optarg; + } + if (match(optarg, /^\[[:=]?|^[:=[:space:]]/)) { + suffix = substr(optarg, RSTART + RLENGTH - 1, 1); + if (suffix == "[") suffix = ""; + } + } + } + specs[i] = option FS optarg FS suffix; + } + for (i = 1; i <= n; i++) { + if (specs[i] == "") continue; + option = substr(specs[i], 1, index(specs[i], FS) - 1); + if (!g_hash[option]++) + g_options[g_option_count++] = specs[i]; + } + } + function process_desc(line) { + gsub(/^[[:space:]]*|[[:space:]]*$/, "", line); + gsub(/[[:space:]][[:space:]]+/, " ", line); + if (line == "") { + if (g_desc != "") return 0; + return 1; + } + if (g_desc != "") g_desc = g_desc " "; + g_desc = g_desc line; + return 1; + } + sub(/^[[:space:]]*__ble_key__/, "", $0) { + flush_pair(); + mode = "key"; + if (match($0, /__ble_desc__/) > 0) { + s_key = substr($0, 1, RSTART - 1); + s_desc = substr($0, RSTART + RLENGTH); + process_key(s_key); + mode = "desc"; + if (!process_desc(s_desc)) mode = ""; + next; + } + } + sub(/^[[:space:]]*__ble_desc__/, "", $0) { + mode = "desc"; + } + mode == "key" { process_key($0); } + mode == "desc" { if (!process_desc($0)) mode = ""; } + END { flush_pair(); } + ' | ble/bin/sort -t "$_ble_term_FS" -k 1 +} +function ble/complete/mandb:help/generate-cache { + local opts=$1 + local -x cfg_usage= cfg_help=1 cfg_plus= cfg_plus_generate= + [[ :$opts: == *:mandb-help-usage:* ]] && cfg_usage=1 + [[ :$opts: == *:mandb-usage:* ]] && cfg_usage=1 cfg_help= + ble/string#match ":$opts:" ':plus-options(=[^:]+)?:' && + cfg_plus=1 cfg_plus_generate=${BASH_REMATCH[1]:1} + local space=$' \t' # for #D1709 (WA gawk 4.0.2) + local rex_argsep='(\[?[:=]| ?|\[)' + local rex_option='[-+](,|[^]:='$space',[]+)('$rex_argsep'(<[^<>]+>|\([^()]+\)|[^-[:space:]])[^[:space:]]*)?' + ble/bin/awk -F "$_ble_term_FS" ' + BEGIN { + cfg_help = ENVIRON["cfg_help"]; + g_indent = -1; + g_keys_count = 0; + g_desc = ""; + cfg_usage = ENVIRON["cfg_usage"]; + g_usage_count = 0; + cfg_plus_generate = ENVIRON["cfg_plus_generate"]; + cfg_plus = ENVIRON["cfg_plus"] cfg_plus_generate; + } + function split_option_optarg_suffix(optspec, _, key, suffix, optarg) { + if (index(optspec, FS) != 0) return ""; + if ((pos = match(optspec, /'"$rex_argsep"'/)) > 0) { + key = substr(optspec, 1, pos - 1); + suffix = substr(optspec, pos + RLENGTH - 1, 1); + if (suffix == "[") suffix = ""; + optarg = substr(optspec, pos); + } else { + key = optspec; + optarg = ""; + suffix = " "; + } + if (key ~ /[^-+'"$_ble_complete_option_chars"']/) return ""; + return key FS optarg FS suffix; + } + function print_entry(entry, _, name) { + name = entry; + sub(/'"$_ble_term_FS"'.*$/, "", name); + if (name ~ /^\+/ && !cfg_plus) return; + if (!g_hash[name]++) # uniq + print entry; + } + { + gsub(/\x1b\[[ -?]*[@-~]/, ""); # CSI seq + gsub(/\x1b[ -\/]*[0-~]/, ""); # ESC seq + gsub(/[\x00-\x1F]/, ""); # Remove all the other C0 chars + } + function generate_plus(_, i, n) { + if (!cfg_plus_generate) return; + n = length(cfg_plus_generate); + for (i = 1; i <= n; i++) + print_entry("+" substr(cfg_plus_generate, i, 1) FS FS FS); + } + function parse_usage(line, _, optspec, optspec1, option, optarg, n, i, o) { + while (match(line, /\[[[:space:]]*([^][]|\[[^][]*\])+[[:space:]]*\]/)) { + optspec = substr(line, RSTART + 1, RLENGTH - 2); + line = substr(line, RSTART + RLENGTH); + while (match(optspec, /([^][|]|\[[^][]*\])+/)) { + optspec1 = substr(optspec, RSTART, RLENGTH); + optspec = substr(optspec, RSTART + RLENGTH); + gsub(/^[[:space:]]+|[[:space:]]+$/, "", optspec1); + if (match(optspec1, /^[-+][^]:='"$space"'[]+/)) { + option = substr(optspec1, RSTART, RLENGTH); + optarg = substr(optspec1, RSTART + RLENGTH); + n = RLENGTH; + if (option ~ /^-.*-/) { + if ((keyinfo = split_option_optarg_suffix(optspec1)) != "") + g_usage[g_usage_count++] = keyinfo; + } else { + o = substr(option, 1, 1); + for (i = 2; i <= n; i++) + if ((keyinfo = split_option_optarg_suffix(o substr(option, i, 1) optarg)) != "") + g_usage[g_usage_count++] = keyinfo; + } + } + } + } + } + function print_usage(_, i) { + for (i = 0; i < g_usage_count; i++) + print_entry(g_usage[i] FS); + } + cfg_usage { + if (NR <= 20 && (g_usage_start || $0 ~ /^[a-zA-Z_0-9]|^[^-[:space:]][^[:space:]]*(: |:)/) ) { + g_usage_start = 1; + parse_usage($0); + } else if (/^[[:space:]]*$/) + cfg_usage = 0; + } + function get_indent(text, _, i, n, ret) { + ret = 0; + n = length(text); + for (i = 1; i <= n; i++) { + c = substr(text, i, 1); + if (c == " ") + ret++; + else if (c == "\t") + ret = (int(ret / 8) + 1) * 8; + else + break; + } + return ret; + } + function flush_data(_, i) { + if (g_indent < 0) return; + for (i = 0; i < g_keys_count; i++) + print_entry(g_keys[i] FS g_desc); + g_indent = -1; + g_keys_count = 0; + g_desc = ""; + } + function register_key(keydef, _, key, keyinfo, keys, nkey, i, optarg) { + if (g_desc != "") flush_data(); + g_indent = get_indent(keydef); + nkey = 0; + for (;;) { + sub(/^,?[[:space:]]+/, "", keydef); + if (match(keydef, /^'"$rex_option"'/) <= 0) break; + key = substr(keydef, 1, RLENGTH); + keydef = substr(keydef, RLENGTH + 1); + sub(/,$/, "", key); + keys[nkey++] = key; + } + if (nkey >= 2) { + optarg = ""; + for (i = nkey; --i >= 0; ) { + if (match(keys[i], /'"$rex_argsep"'/) > 0) { + optarg = substr(keys[i], RSTART); + sub(/^[[:space:]]+/, "", optarg); + if (optarg !~ /[A-Z]|<.+>/) optarg = ""; + } else if (optarg != ""){ + if (keys[i] ~ /^[-+].$/) { + optarg2 = optarg; + sub(/^\[=/, "[", optarg2); + sub(/^=/, "", optarg2); + sub(/^[^[:space:][]/, " &", optarg2); + keys[i] = keys[i] optarg2; + } else { + optarg2 = optarg; + if (optarg2 ~ /^\[[^:=]/) + sub(/^\[/, "[=", optarg2); + else if (optarg2 ~ /^[^:=[:space:][]/) + optarg2 = " " optarg2; + keys[i] = keys[i] optarg2; + } + } + } + } + for (i = 0; i < nkey; i++) + if ((keyinfo = split_option_optarg_suffix(keys[i])) != "") + g_keys[g_keys_count++] = keyinfo; + } + function append_desc(desc) { + gsub(/^[[:space:]]+|[[:space:]]$/, "", desc); + if (desc == "") return; + if (g_desc == "") + g_desc = desc; + else + g_desc = g_desc " " desc; + } + cfg_help && match($0, /^[[:space:]]*'"$rex_option"'(,?[[:space:]]+'"$rex_option"')*/) { + key = substr($0, 1, RLENGTH); + desc = substr($0, RLENGTH + 1); + if (desc ~ /^,/) next; + register_key(key); + append_desc(desc); + next; + } + g_indent >= 0 { + sub(/[[:space:]]+$/, ""); + indent = get_indent($0); + if (indent <= g_indent) + flush_data(); + else + append_desc($0); + } + END { + flush_data(); + print_usage(); + generate_plus(); + } + ' | ble/bin/sort -t "$_ble_term_FS" -k 1 +} +function ble/complete/mandb:_parse_help/inject { + ble/is-function _parse_help || return 0 + ble/function#advice before _parse_help 'ble/complete/mandb:_parse_help/generate-cache "${ADVICE_WORDS[1]}" "${ADVICE_WORDS[2]}"' + ble/function#advice before _longopt 'ble/complete/mandb:_parse_help/generate-cache "${ADVICE_WORDS[1]}"' + ble/function#advice before _parse_usage 'ble/complete/mandb:_parse_help/generate-cache "${ADVICE_WORDS[1]}" "${ADVICE_WORDS[2]}" usage' + function ble/complete/mandb:_parse_help/inject { return 0; } +} +function ble/string#hash-pjw { + local size=${2:-32} + local S=${3:-$(((size+7)/8))} # shift 4 + local C=$((size-2*S)) # co-shift 24 + local M=$(((1<<size-S)-1)) # mask 0x0FFFFFFF + local N=$(((1<<S)-1<<S)) # mask2 0x000000F0 + ble/util/s2bytes "$1" + local c h=0 + for c in "${ret[@]}"; do + ((h=(h<<S)+c,h=(h^h>>C&N)&M)) + done + ret=$h +} +function ble/complete/mandb:_parse_help/generate-cache { + [[ $_ble_attached ]] || return 0 + local command=$1; [[ $1 == ble*/* ]] || command=${1##*/} + local ret; ble/string#hash-pjw "${*:2}" 64; local hash=$ret + local lc_messages=${LC_ALL:-${LC_MESSAGES:-${LANG:-C}}} + local mandb_cache_dir=$_ble_base_cache/complete.mandb/${lc_messages//'/'/%} + local subcache; ble/util/sprintf subcache '%s.%014x' "$mandb_cache_dir/_parse_help.d/$command" "$hash" + [[ -s $subcache && $subcache -nt $_ble_base/lib/core-complete.sh ]] && return 0 + ble/util/mkd "${subcache%/*}" + if [[ $1 == - ]]; then + ble/complete/mandb:help/generate-cache "$3" + else + local args default_option=--help + [[ :$3: == *:usage:* ]] && default_option=--usage + ble/string#split-words args "${2:-$default_option}" + "$1" "${args[@]}" 2>&1 | ble/complete/mandb:help/generate-cache "$3" + fi >| "$subcache" +} +function ble/complete/mandb/generate-cache { + local command=${1##*/} + local lc_messages=${LC_ALL:-${LC_MESSAGES:-${LANG:-C}}} + local mandb_cache_dir=$_ble_base_cache/complete.mandb/${lc_messages//'/'/%} + local fcache=$mandb_cache_dir/$command + local cmdspec_opts; ble/cmdspec/opts#load "$command" + [[ :$cmdspec_opts: == *:no-options:* ]] && return 1 + if ble/opts#extract-all-optargs "$cmdspec_opts" mandb-help --help; then + local -a helpspecs; helpspecs=("${ret[@]}") + local subcache=$mandb_cache_dir/help.d/$command + if ! [[ -s $subcache && $subcache -nt $_ble_base/lib/core-complete.sh ]]; then + ble/util/mkd "${subcache%/*}" + local helpspec + for helpspec in "${helpspecs[@]}"; do + if [[ $helpspec == %* ]]; then + builtin eval -- "${helpspec:1}" + elif [[ $helpspec == @* ]]; then + ble/util/print "${helpspec:1}" + else + ble/string#split-words helpspec "${helpspec#+}" + "$command" "${helpspec[@]}" 2>&1 + fi + done | ble/complete/mandb:help/generate-cache "$cmdspec_opts" >| "$subcache" + fi + fi + if [[ :$cmdspec_opts: != *:mandb-disable-man:* ]] && ble/bin#has "$1"; then + local subcache=$mandb_cache_dir/man.d/$command + if ! [[ -s $subcache && $subcache -nt $_ble_base/lib/core-complete.sh ]]; then + ble/util/mkd "${subcache%/*}" + ble/complete/mandb/.generate-cache-from-man "$command" >| "$subcache" + fi + fi + local -a subcaches=() + local subcache update= + ble/complete/util/eval-pathname-expansion '"$mandb_cache_dir"/_parse_help.d/"$command".??????????????' + for subcache in "${ret[@]}" "$mandb_cache_dir"/{help,man}.d/"$command"; do + if [[ -s $subcache && $subcache -nt $_ble_base/lib/core-complete.sh ]]; then + ble/array#push subcaches "$subcache" + [[ $fcache -nt $subcache ]] || update=1 + fi + done + if [[ $update ]]; then + local fs=$_ble_term_FS + ble/bin/awk -F "$_ble_term_FS" ' + BEGIN { plus_count = 0; nodesc_count = 0; } + $4 == "" { + if ($1 ~ /^\+/) { + plus_name[plus_count] = $1; + plus_entry[plus_count] = $0; + plus_count++; + } else { + nodesc_name[nodesc_count] = $1; + nodesc_entry[nodesc_count] = $0; + nodesc_count++; + } + next; + } + !hash[$1] { hash[$1] = $0; print; } + END { + for (i = 0; i < nodesc_count; i++) { + if (!hash[nodesc_name[i]]) { + hash[nodesc_name[i]] = nodesc_entry[i]; + print nodesc_entry[i]; + } + } + for (i = 0; i < plus_count; i++) { + name = plus_name[i]; + if (hash[name]) continue; + split(plus_entry[i], record, FS); + optarg = record[2]; + suffix = record[3]; + desc = ""; + mname = name; + sub(/^\+/, "-", mname); + if (hash[mname]) { + if (!optarg) { + split(hash[mname], record, FS); + optarg = record[2]; + suffix = record[3]; + } + desc = hash[mname]; + sub(/^[^'$fs']*'$fs'[^'$fs']*'$fs'[^'$fs']*'$fs'/, "", desc); + if (desc) desc = "\033[1mReverse[\033[m " desc " \033[;1m]\033[m"; + } + if (!desc) desc = "reverse of \033[4m" mname "\033[m"; + hash[name] = name FS optarg FS suffix FS desc; + print hash[name]; + } + } + ' "${subcaches[@]}" >| "$fcache" + fi + ret=$fcache + [[ -s $fcache ]] +} +function ble/complete/mandb/load-cache { + ret=() + ble/complete/mandb/generate-cache "$@" && + ble/util/mapfile ret < "$ret" +} +function ble/complete/source:option/.is-option-context { + local rexrej rexreq stopat + ble/progcolor/stop-option#init "$cmdspec_opts" + if [[ $stopat ]] && ((stopat<=$#)); then + return 1 + elif [[ ! $rexrej$rexreq ]]; then + return 0 + fi + local word ret + for word; do + ble/syntax:bash/simple-word/is-simple "$word" && + ble/syntax:bash/simple-word/eval "$word" noglob && + ble/progcolor/stop-option#test "$ret" && + return 1 + done + return 0 +} +function ble/complete/source:option { + local rex='^-[-+'$_ble_complete_option_chars']*$|^\+[_'$_ble_complete_option_chars']*$' + [[ ! $COMPV || $COMPV =~ $rex ]] || return 0 + local COMPS=$COMPS COMPV=$COMPV + ble/complete/source/reduce-compv-for-ambiguous-match + [[ :$comp_type: == *:[maA]:* ]] && local COMP2=$COMP1 + local comp_words comp_line comp_point comp_cword + ble/syntax:bash/extract-command "$COMP2" || return 1 + local -a prev_args=() + ((comp_cword>=1)) && prev_args=("${comp_words[@]:1:comp_cword-1}") + local cmd=${comp_words[0]} + local alias_checked=' ' + while local ret; ! ble/complete/mandb/load-cache "$cmd"; do + alias_checked=$alias_checked$cmd' ' + ble/alias#expand "$cmd" || return 1 + local words; ble/string#split-words ret "$ret"; words=("${ret[@]}") + local iword=0 rex='^[_a-zA-Z][_a-zA-Z0-9]*\+?=' + while [[ ${words[iword]} =~ $rex ]]; do ((iword++)); done + [[ ${words[iword]} && $alias_checked != *" ${words[iword]} "* ]] || return 1 + prev_args=("${words[@]:iword+1}" "${prev_args[@]}") + cmd=${words[iret]} + done + local -a entries; entries=("${ret[@]}") + local ret cmdspec_opts= + ble/syntax:bash/simple-word/is-simple "$cmd" && + ble/syntax:bash/simple-word/eval "$cmd" noglob && + ble/cmdspec/opts#load "$ret" + ble/complete/source:option/.is-option-context "${prev_args[@]}" || return 1 + local "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe + ble/complete/cand/yield.initialize mandb + local entry fs=$_ble_term_FS has_desc= + for entry in "${entries[@]}"; do + ((cand_iloop++%bleopt_complete_polling_cycle==0)) && + ble/complete/check-cancel && return 148 + local CAND=${entry%%$_ble_term_FS*} + [[ $CAND == "$COMPV"* ]] || continue + ble/complete/cand/yield mandb "$CAND" "$entry" + [[ $entry == *"$fs"*"$fs"*"$fs"?* ]] && has_desc=1 + done + [[ $has_desc ]] && bleopt complete_menu_style=desc +} +function ble/complete/source:argument/.generate-user-defined-completion { + shopt -q progcomp || return 1 + [[ :$comp_type: == *:[maA]:* ]] && local COMP2=$COMP1 + local comp_words comp_line comp_point comp_cword + ble/syntax:bash/extract-command "$COMP2" || return 1 + local forward_words= + ((comp_cword)) && IFS=' ' builtin eval 'forward_words="${comp_words[*]::comp_cword} "' + local comp2_in_word=$((comp_point-${#forward_words})) + local comp1_in_word=$((comp2_in_word-(COMP2-COMP1))) + if ((comp1_in_word>0)); then + local w=${comp_words[comp_cword]} + comp_words=("${comp_words[@]::comp_cword}" "${w::comp1_in_word}" "${w:comp1_in_word}" "${comp_words[@]:comp_cword+1}") + IFS=' ' builtin eval 'comp_line="${comp_words[*]}"' + ((comp_cword++,comp_point++)) + ((comp2_in_word=COMP2-COMP1,comp1_in_word=0)) + fi + if [[ $COMPV && :$comp_type: == *:[maA]:* ]]; then + local oword=${comp_words[comp_cword]::comp2_in_word} ins + local ins=; [[ :$comp_type: == *:a:* ]] && ins=${COMPV::1} + local ret comps_flags= comps_fixed= # referenced in ble/complete/string#escape-for-completion-context + if [[ $oword ]]; then + local simple_flags simple_ibrace + ble/syntax:bash/simple-word/reconstruct-incomplete-word "$oword" || return 1 + comps_flags=v$simple_flags + ((${simple_ibrace%:*})) && comps_fixed=1 + fi + ble/complete/string#escape-for-completion-context "$ins" c; ins=$ret + ble/util/unlocal comps_flags comps_fixed + ((comp_point+=${#ins})) + comp_words=("${comp_words[@]::comp_cword}" "$oword$ins" "${comp_words[@]:comp_cword+1}") + IFS=' ' builtin eval 'comp_line="${comp_words[*]}"' + ((comp2_in_word+=${#ins})) + fi + local opts=$1 + if [[ :$opts: == *:initial:* ]]; then + ble/complete/progcomp/.compgen initial + else + ble/complete/progcomp "${comp_words[0]}" + fi +} +function ble/complete/source:argument { + local comp_opts=: + ble/complete/source:sabbrev + if [[ $comps_flags == *f* && $COMPS != *\* && :$comp_type: != *:[maA]:* ]]; then + local ret simple_flags simple_ibrace + ble/syntax:bash/simple-word/reconstruct-incomplete-word "$COMPS" + ble/complete/source/eval-simple-word "$ret*" && ((${#ret[*]})) && + ble/complete/cand/yield-filenames file "${ret[@]}" + (($?==148)) && return 148 + fi + local old_cand_count=$cand_count + ble/complete/source:argument/.generate-user-defined-completion; local ext=$? + ((ext==148||cand_count>old_cand_count)) && return "$ext" + [[ $comp_opts == *:ble/no-default:* ]] && return "$ext" + ble/complete/source:option; local ext=$? + ((ext==148||cand_count>old_cand_count&&${#COMPV})) && return "$ext" + if [[ $comp_opts == *:dirnames:* ]]; then + ble/complete/source:dir + else + ble/complete/source:file + fi; local ext=$? + ((ext==148||cand_count>old_cand_count)) && return "$ext" + if local rex='^/?[-_a-zA-Z0-9.]+[:=]|^-[^-/=:]'; [[ $COMPV =~ $rex ]]; then + local prefix=$BASH_REMATCH value=${COMPV:${#BASH_REMATCH}} + local COMP_PREFIX=$prefix + [[ :$comp_type: != *:[maA]:* && $value =~ ^.+/ ]] && + COMP_PREFIX=$prefix${BASH_REMATCH[0]} + local ret cand "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe + ble/complete/source:file/.construct-pathname-pattern "$value" + ble/complete/util/eval-pathname-expansion "$ret"; (($?==148)) && return 148 + ble/complete/source/test-limit ${#ret[@]} || return 1 + ble/complete/cand/yield.initialize file_rhs + for cand in "${ret[@]}"; do + [[ -e $cand || -h $cand ]] || continue + [[ $FIGNORE ]] && ! ble/complete/.fignore/filter "$cand" && continue + ble/complete/cand/yield file_rhs "$prefix$cand" "$prefix" + done + fi +} +function ble/complete/source/compgen { + [[ $comps_flags == *v* ]] || return 1 + local COMPS=$COMPS COMPV=$COMPV + ble/complete/source/reduce-compv-for-ambiguous-match + local compgen_action=$1 + local action=$2 + local data=$3 + local q="'" Q="'\''" + local compv_quoted="'${COMPV//$q/$Q}'" + local arr + ble/util/assign-array arr 'builtin compgen -A "$compgen_action" -- "$compv_quoted"' + ble/complete/source/test-limit ${#arr[@]} || return 1 + [[ $1 != '=' && ${#arr[@]} == 1 && $arr == "$COMPV" ]] && return 0 + local cand "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe + ble/complete/cand/yield.initialize "$action" + for cand in "${arr[@]}"; do + ((cand_iloop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148 + ble/complete/cand/yield "$action" "$cand" "$data" + done +} +function ble/complete/source:variable { + local data= + case $1 in + ('=') data=assignment ;; + ('b') data=braced ;; + ('a') data=arithmetic ;; + ('n') data=nosuffix ;; + ('w'|*) data=word ;; + esac + ble/complete/source/compgen variable variable "$data" +} +function ble/complete/source:user { + ble/complete/source/compgen user word +} +function ble/complete/source:hostname { + ble/complete/source/compgen hostname word +} +function ble/complete/complete/determine-context-from-opts { + local opts=$1 + context=syntax + if local rex=':context=([^:]+):'; [[ :$opts: =~ $rex ]]; then + local rematch1=${BASH_REMATCH[1]} + if ble/is-function ble/complete/context:"$rematch1"/generate-sources; then + context=$rematch1 + else + ble/util/print "ble/widget/complete: unknown context '$rematch1'" >&2 + fi + fi +} +function ble/complete/context/filter-prefix-sources { + local -a filtered_sources=() + local src asrc + for src in "${sources[@]}"; do + ble/string#split-words asrc "$src" + local comp1=${asrc[1]} + ((comp1<comp_index)) && + ble/array#push filtered_sources "$src" + done + sources=("${filtered_sources[@]}") + ((${#sources[@]})) +} +function ble/complete/context/overwrite-sources { + local source_name=$1 + local -a new_sources=() + local src asrc mark + for src in "${sources[@]}"; do + ble/string#split-words asrc "$src" + [[ ${mark[asrc[1]]} ]] && continue + ble/array#push new_sources "$source_name ${asrc[1]}" + mark[asrc[1]]=1 + done + ((${#new_sources[@]})) || + ble/array#push new_sources "$source_name $comp_index" + sources=("${new_sources[@]}") +} +function ble/complete/context:syntax/generate-sources { + ble/syntax/import + ble-edit/content/update-syntax + ble/cmdspec/initialize # load user configruation + ble/syntax/completion-context/generate "$comp_text" "$comp_index" + ((${#sources[@]})) +} +function ble/complete/context:filename/generate-sources { + ble/complete/context:syntax/generate-sources || return "$?" + ble/complete/context/overwrite-sources file +} +function ble/complete/context:command/generate-sources { + ble/complete/context:syntax/generate-sources || return "$?" + ble/complete/context/overwrite-sources command +} +function ble/complete/context:variable/generate-sources { + ble/complete/context:syntax/generate-sources || return "$?" + ble/complete/context/overwrite-sources variable +} +function ble/complete/context:username/generate-sources { + ble/complete/context:syntax/generate-sources || return "$?" + ble/complete/context/overwrite-sources user +} +function ble/complete/context:hostname/generate-sources { + ble/complete/context:syntax/generate-sources || return "$?" + ble/complete/context/overwrite-sources hostname +} +function ble/complete/context:glob/generate-sources { + comp_type=$comp_type:raw + ble/complete/context:syntax/generate-sources || return "$?" + ble/complete/context/overwrite-sources glob +} +function ble/complete/source:glob { + [[ $comps_flags == *v* ]] || return 1 + [[ :$comp_type: == *:[maA]:* ]] && return 1 + local pattern=$COMPV + ble/complete/source/eval-simple-word "$pattern"; (($?==148)) && return 148 + if ((!${#ret[@]})) && [[ $pattern != *'*' ]]; then + ble/complete/source/eval-simple-word "$pattern*"; (($?==148)) && return 148 + fi + local cand action=file "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe + ble/complete/cand/yield.initialize "$action" + for cand in "${ret[@]}"; do + ((cand_iloop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148 + ble/complete/cand/yield "$action" "$cand" + done +} +function ble/complete/context:dynamic-history/generate-sources { + comp_type=$comp_type:raw + ble/complete/context:syntax/generate-sources || return "$?" + ble/complete/context/overwrite-sources dynamic-history +} +function ble/complete/source:dynamic-history { + [[ $comps_flags == *v* ]] || return 1 + [[ :$comp_type: == *:[maA]:* ]] && return 1 + [[ $COMPV ]] || return 1 + local wordbreaks; ble/complete/get-wordbreaks + wordbreaks=${wordbreaks//$'\n'} + local ret; ble/string#escape-for-extended-regex "$COMPV" + local rex_needle='(^|['$wordbreaks'])'$ret'[^'$wordbreaks']+' + local rex_wordbreaks='['$wordbreaks']' + ble/util/assign-array ret 'HISTTIMEFORMAT= builtin history | ble/bin/grep -Eo "$rex_needle" | ble/bin/sed "s/^$rex_wordbreaks//" | ble/bin/sort -u' + local cand action=literal-word "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe + ble/complete/cand/yield.initialize "$action" + for cand in "${ret[@]}"; do + ((cand_iloop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148 + ble/complete/cand/yield "$action" "$cand" + done +} +function ble/complete/util/construct-ambiguous-regex { + local text=$1 fixlen=${2:-1} + local opt_icase=; [[ :$comp_type: == *:i:* ]] && opt_icase=1 + local -a buff=() + local i=0 n=${#text} ch= + for ((i=0;i<n;i++)); do + ((i>=fixlen)) && ble/array#push buff '.*' + ch=${text:i:1} + if [[ $ch == [a-zA-Z] ]]; then + if [[ $opt_icase ]]; then + ble/string#toggle-case "$ch" + ch=[$ch$ret] + fi + else + ble/string#escape-for-extended-regex "$ch"; ch=$ret + fi + ble/array#push buff "$ch" + done + IFS= builtin eval 'ret="${buff[*]}"' +} +function ble/complete/util/construct-glob-pattern { + local text=$1 + if [[ :$comp_type: == *:i:* ]]; then + local i n=${#text} c + local -a buff=() + for ((i=0;i<n;i++)); do + c=${text:i:1} + if [[ $c == [a-zA-Z] ]]; then + ble/string#toggle-case "$c" + c=[$c$ret] + else + ble/string#escape-for-bash-glob "$c"; c=$ret + fi + ble/array#push buff "$c" + done + IFS= builtin eval 'ret="${buff[*]}"' + else + ble/string#escape-for-bash-glob "$1" + fi +} +function ble/complete/.fignore/prepare { + _fignore=() + local i=0 leaf tmp + ble/string#split tmp ':' "$FIGNORE" + for leaf in "${tmp[@]}"; do + [[ $leaf ]] && _fignore[i++]="$leaf" + done +} +function ble/complete/.fignore/filter { + local pat + for pat in "${_fignore[@]}"; do + [[ $1 == *"$pat" ]] && return 1 + done + return 0 +} +function ble/complete/candidates/.pick-nearest-sources { + COMP1= COMP2=$comp_index + nearest_sources=() + local -a unused_sources=() + local src asrc + for src in "${remaining_sources[@]}"; do + ble/string#split-words asrc "$src" + if ((COMP1<asrc[1])); then + COMP1=${asrc[1]} + ble/array#push unused_sources "${nearest_sources[@]}" + nearest_sources=("$src") + elif ((COMP1==asrc[1])); then + ble/array#push nearest_sources "$src" + else + ble/array#push unused_sources "$src" + fi + done + remaining_sources=("${unused_sources[@]}") + COMPS=${comp_text:COMP1:COMP2-COMP1} + comps_flags= + comps_fixed= + if [[ ! $COMPS ]]; then + comps_flags=${comps_flags}v COMPV= + elif local ret simple_flags simple_ibrace; ble/syntax:bash/simple-word/reconstruct-incomplete-word "$COMPS"; then + local reconstructed=$ret + if [[ :$comp_type: == *:raw:* ]]; then + if ((${simple_ibrace%:*})); then + COMPV= + else + comps_flags=$comps_flags${simple_flags}v + COMPV=$reconstructed + fi + elif ble/complete/source/eval-simple-word "$reconstructed"; local ext=$?; ((ext==148)) && return 148; ((ext==0)); then + COMPV=("${ret[@]}") + comps_flags=$comps_flags${simple_flags}v + if ((${simple_ibrace%:*})); then + ble/complete/source/eval-simple-word "${reconstructed::${simple_ibrace#*:}}" single; (($?==148)) && return 148 + comps_fixed=${simple_ibrace%:*}:$ret + comps_flags=${comps_flags}x + fi + else + COMPV= + comps_flags=$comps_flags${simple_flags}f + fi + [[ $COMPS =~ $rex_raw_paramx ]] && comps_flags=${comps_flags}p + else + COMPV= + fi +} +function ble/complete/candidates/clear { + cand_count=0 + cand_cand=() + cand_word=() + cand_pack=() +} +function ble/complete/candidates/.filter-by-command { + local command=$1 + local i j=0 + local -a prop=() cand=() word=() show=() data=() + for ((i=0;i<cand_count;i++)); do + ((i%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148 + builtin eval -- "$command" || continue + cand[j]=${cand_cand[i]} + word[j]=${cand_word[i]} + data[j]=${cand_pack[i]} + ((j++)) + done + cand_count=$j + cand_cand=("${cand[@]}") + cand_word=("${word[@]}") + cand_pack=("${data[@]}") +} +function ble/complete/candidates/.filter-by-regex { + local rex_filter=$1 + ble/complete/candidates/.filter-by-command '[[ ${cand_cand[i]} =~ $rex_filter ]]' +} +function ble/complete/candidates/.filter-by-glob { + local globpat=$1 + ble/complete/candidates/.filter-by-command '[[ ${cand_cand[i]} == $globpat ]]' +} +function ble/complete/candidates/.filter-word-by-prefix { + local prefix=$1 + ble/complete/candidates/.filter-by-command '[[ ${cand_word[i]} == "$prefix"* ]]' +} +function ble/complete/candidates/.initialize-rex_raw_paramx { + local element=$_ble_syntax_bash_simple_rex_element + local open_dquot=$_ble_syntax_bash_simple_rex_open_dquot + rex_raw_paramx='^('$element'*('$open_dquot')?)\$[a-zA-Z_][a-zA-Z_0-9]*$' +} +function ble/complete/candidates/filter#init { + comp_filter_type=$1 + comp_filter_pattern= + ble/complete/candidates/filter:"$comp_filter_type"/init "$2" +} +function ble/complete/candidates/filter#test { + ble/complete/candidates/filter:"$comp_filter_type"/test "$1" +} +function ble/complete/candidates/filter:none/init { ble/complete/candidates/filter:head/init "$@"; } +function ble/complete/candidates/filter:none/test { true; } +function ble/complete/candidates/filter:none/count-match-chars { ble/complete/candidates/filter:head/count-match-chars "$@"; } +function ble/complete/candidates/filter:none/match { ble/complete/candidates/filter:head/match "$@"; } +function ble/complete/candidates/filter:head/init { + local ret; ble/complete/util/construct-glob-pattern "$1" + comp_filter_pattern=$ret* +} +function ble/complete/candidates/filter:head/count-match-chars { # unused but for completeness + local value=$1 compv=$COMPV + if [[ :$comp_type: == *:i:* ]]; then + ble/string#tolower "$value"; value=$ret + ble/string#tolower "$compv"; compv=$ret + fi + if [[ $value == "$compv"* ]]; then + ret=${#compv} + elif [[ $compv == "$value"* ]]; then + ret=${#value} + else + ret=0 + fi +} +function ble/complete/candidates/filter:head/test { [[ $1 == $comp_filter_pattern ]]; } +function ble/complete/candidates/filter:head/match { + local needle=$1 text=$2 + if [[ :$comp_type: == *:i:* ]]; then + ble/string#tolower "$needle"; needle=$ret + ble/string#tolower "$text"; text=$ret + fi + if [[ ! $needle || ! $text ]]; then + ret=() + elif [[ $text == "$needle"* ]]; then + ret=(0 ${#needle}) + return 0 + elif [[ $text == "${needle::${#text}}" ]]; then + ret=(0 ${#text}) + return 0 + else + ret=() + return 1 + fi +} +function ble/complete/candidates/filter:substr/init { + local ret; ble/complete/util/construct-glob-pattern "$1" + comp_filter_pattern=*$ret* +} +function ble/complete/candidates/filter:substr/count-match-chars { + local value=$1 compv=$COMPV + if [[ :$comp_type: == *:i:* ]]; then + ble/string#tolower "$value"; value=$ret + ble/string#tolower "$compv"; compv=$ret + fi + if [[ $value == *"$compv"* ]]; then + ret=${#compv} + return 0 + fi + ble/complete/string#common-suffix-prefix "$value" "$compv" + ret=${#ret} +} +function ble/complete/candidates/filter:substr/test { [[ $1 == $comp_filter_pattern ]]; } +function ble/complete/candidates/filter:substr/match { + local needle=$1 text=$2 + if [[ :$comp_type: == *:i:* ]]; then + ble/string#tolower "$needle"; needle=$ret + ble/string#tolower "$text"; text=$ret + fi + if [[ ! $needle ]]; then + ret=() + elif [[ $text == *"$needle"* ]]; then + text=${text%%"$needle"*} + local beg=${#text} + local end=$((beg+${#needle})) + ret=("$beg" "$end") + elif ble/complete/string#common-suffix-prefix "$text" "$needle"; ((${#ret})); then + local end=${#text} + local beg=$((end-${#ret})) + ret=("$beg" "$end") + else + ret=() + fi +} +function ble/complete/candidates/filter:hsubseq/.determine-fixlen { + fixlen=${1:-1} + if [[ $comps_fixed ]]; then + local compv_fixed_part=${comps_fixed#*:} + [[ $compv_fixed_part ]] && fixlen=${#compv_fixed_part} + fi +} +function ble/complete/candidates/filter:hsubseq/init { + local fixlen; ble/complete/candidates/filter:hsubseq/.determine-fixlen "$2" + local ret; ble/complete/util/construct-ambiguous-regex "$1" "$fixlen" + comp_filter_pattern=^$ret +} +function ble/complete/candidates/filter:hsubseq/count-match-chars { + local value=$1 compv=$COMPV + if [[ :$comp_type: == *:i:* ]]; then + ble/string#tolower "$value"; value=$ret + ble/string#tolower "$compv"; compv=$ret + fi + local fixlen + ble/complete/candidates/filter:hsubseq/.determine-fixlen "$2" + [[ $value == "${compv::fixlen}"* ]] || return 1 + value=${value:fixlen} + local i n=${#COMPV} + for ((i=fixlen;i<n;i++)); do + local a=${value%%"${compv:i:1}"*} + [[ $a == "$value" ]] && { ret=$i; return 0; } + value=${value:${#a}+1} + done + ret=$n +} +function ble/complete/candidates/filter:hsubseq/test { [[ $1 =~ $comp_filter_pattern ]]; } +function ble/complete/candidates/filter:hsubseq/match { + local needle=$1 text=$2 + if [[ :$comp_type: == *:i:* ]]; then + ble/string#tolower "$needle"; needle=$ret + ble/string#tolower "$text"; text=$ret + fi + local fixlen; ble/complete/candidates/filter:hsubseq/.determine-fixlen "$3" + local prefix=${needle::fixlen} + if [[ $text != "$prefix"* ]]; then + if [[ $text && $text == "${prefix::${#text}}" ]]; then + ret=(0 ${#text}) + else + ret=() + fi + return 0 + fi + local pN=${#text} iN=${#needle} + local first=1 + ret=() + while :; do + if [[ $first ]]; then + first= + local p0=0 p=${#prefix} i=${#prefix} + else + ((i<iN)) || return 0 + while ((p<pN)) && [[ ${text:p:1} != "${needle:i:1}" ]]; do + ((p++)) + done + ((p<pN)) || return 1 + p0=$p + fi + while ((i<iN&&p<pN)) && [[ ${text:p:1} == "${needle:i:1}" ]]; do + ((p++,i++)) + done + ((p0<p)) && ble/array#push ret "$p0" "$p" + done +} +function ble/complete/candidates/filter:subseq/init { + [[ $comps_fixed ]] && return 1 + ble/complete/candidates/filter:hsubseq/init "$1" 0 +} +function ble/complete/candidates/filter:subseq/count-match-chars { + ble/complete/candidates/filter:hsubseq/count-match-chars "$1" 0 +} +function ble/complete/candidates/filter:subseq/test { [[ $1 =~ $comp_filter_pattern ]]; } +function ble/complete/candidates/filter:subseq/match { + ble/complete/candidates/filter:hsubseq/match "$1" "$2" 0 +} +function ble/complete/candidates/generate-with-filter { + local filter_type=$1 opts=$2 + local -a remaining_sources nearest_sources + remaining_sources=("${sources[@]}") + local src asrc source + while ((${#remaining_sources[@]})); do + nearest_sources=() + ble/complete/candidates/.pick-nearest-sources; (($?==148)) && return 148 + [[ ! $COMPV && :$opts: == *:no-empty:* ]] && continue + local comp_filter_type + local comp_filter_pattern + ble/complete/candidates/filter#init "$filter_type" "$COMPV" || continue + for src in "${nearest_sources[@]}"; do + ble/string#split-words asrc "$src" + ble/string#split source : "${asrc[0]}" + local COMP_PREFIX= # 既定値 (yield-candidate で参照) + ble/complete/source:"${source[@]}" + ble/complete/check-cancel && return 148 + done + [[ $comps_fixed ]] && + ble/complete/candidates/.filter-word-by-prefix "${COMPS::${comps_fixed%%:*}}" + ((cand_count)) && return 0 + done + return 0 +} +function ble/complete/candidates/comp_type#read-rl-variables { + ble/util/test-rl-variable completion-ignore-case 0 && comp_type=${comp_type}:i + ble/util/test-rl-variable visible-stats 0 && comp_type=${comp_type}:vstat + ble/util/test-rl-variable mark-directories 1 && comp_type=${comp_type}:markdir + ble/util/test-rl-variable mark-symlinked-directories 1 && comp_type=${comp_type}:marksymdir + ble/util/test-rl-variable match-hidden-files 1 && comp_type=${comp_type}:match-hidden + ble/util/test-rl-variable menu-complete-display-prefix 0 && comp_type=${comp_type}:menu-show-prefix + comp_type=$comp_type:menu-color:menu-color-match +} +function ble/complete/candidates/generate { + local opts=$1 + local flag_force_fignore= + local flag_source_filter= + local -a _fignore=() + if [[ $FIGNORE ]]; then + ble/complete/.fignore/prepare + ((${#_fignore[@]})) && shopt -q force_fignore && flag_force_fignore=1 + fi + local rex_raw_paramx + ble/complete/candidates/.initialize-rex_raw_paramx + ble/complete/candidates/comp_type#read-rl-variables + local cand_iloop=0 + ble/complete/candidates/clear + ble/complete/candidates/generate-with-filter none "$opts" || return "$?" + ((cand_count)) && return 0 + if [[ $bleopt_complete_ambiguous && $COMPV ]]; then + local original_comp_type=$comp_type + comp_type=${original_comp_type}:m + ble/complete/candidates/generate-with-filter substr "$opts" || return "$?" + ((cand_count)) && return 0 + comp_type=${original_comp_type}:a + ble/complete/candidates/generate-with-filter hsubseq "$opts" || return "$?" + ((cand_count)) && return 0 + comp_type=${original_comp_type}:A + ble/complete/candidates/generate-with-filter subseq "$opts" || return "$?" + ((cand_count)) && return 0 + comp_type=$original_comp_type + fi + return 0 +} +function ble/complete/candidates/determine-common-prefix/.apply-partial-comps { + local word0=$COMPS word1=$common fixed= + if [[ $comps_fixed ]]; then + local fixlen=${comps_fixed%%:*} + fixed=${word0::fixlen} + word0=${word0:fixlen} + word1=${word1:fixlen} + fi + local ret spec path spec0 path0 spec1 path1 + ble/complete/source/evaluate-path-spec "$word0"; (($?==148)) && return 148; spec0=("${spec[@]}") path0=("${path[@]}") + ble/complete/source/evaluate-path-spec "$word1"; (($?==148)) && return 148; spec1=("${spec[@]}") path1=("${path[@]}") + local i=${#path1[@]} + while ((i--)); do + if ble/array#last-index path0 "${path1[i]}"; then + local elem=${spec1[i]} # workaround bash-3.1 ${#arr[i]} bug + word1=${spec0[ret]}${word1:${#elem}} + break + fi + done + common=$fixed$word1 +} +function ble/complete/candidates/determine-common-prefix { + local common=${cand_word[0]} + local clen=${#common} + if ((cand_count>1)); then + local unset_nocasematch= flag_tolower= + if [[ :$comp_type: == *:i:* ]]; then + if ((_ble_bash<30100)); then + flag_tolower=1 + ble/string#tolower "$common"; common=$ret + else + unset_nocasematch=1 + shopt -s nocasematch + fi + fi + local word loop=0 + for word in "${cand_word[@]:1}"; do + ((loop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && break + if [[ $flag_tolower ]]; then + ble/string#tolower "$word"; word=$ret + fi + ((clen>${#word}&&(clen=${#word}))) + while [[ ${word::clen} != "${common::clen}" ]]; do + ((clen--)) + done + common=${common::clen} + done + [[ $unset_nocasematch ]] && shopt -u nocasematch + ble/complete/check-cancel && return 148 + [[ $flag_tolower ]] && common=${cand_word[0]::${#common}} + fi + if [[ $common != "$COMPS"* && ! ( $cand_count -eq 1 && $comp_type == *:i:* ) ]]; then + ble/complete/candidates/determine-common-prefix/.apply-partial-comps + fi + if ((cand_count>1)) && [[ $common != "$COMPS"* ]]; then + local common0=$common + common=$COMPS # 取り敢えず補完挿入をキャンセル + if [[ :$comp_type: == *:[maAi]:* ]]; then + local simple_flags simple_ibrace + if ble/syntax:bash/simple-word/reconstruct-incomplete-word "$common0"; then + local common_reconstructed=$ret + local value=$ret filter_type=head + case :$comp_type: in + (*:m:*) filter_type=substr ;; + (*:a:*) filter_type=hsubseq ;; + (*:A:*) filter_type=subseq ;; + esac + local is_processed= + ble/complete/source/eval-simple-word "$common_reconstructed" single; local ext=$? + ((ext==148)) && return 148 + if ((ext==0)) && ble/complete/candidates/filter:"$filter_type"/count-match-chars "$ret"; then + if [[ $filter_type == head ]] && ((ret<${#COMPV})); then + is_processed=1 + [[ $bleopt_complete_allow_reduction ]] && common=$common0 + elif ((ret)); then + is_processed=1 + ble/string#escape-for-bash-specialchars "${COMPV:ret}" c + common=$common0$ret + fi + fi + if [[ ! $is_processed ]] && + local notilde=\'\' && + ble/syntax:bash/simple-word/reconstruct-incomplete-word "$COMPS" && + ble/syntax:bash/simple-word/eval "$notilde$ret" noglob && + local compv_notilde=$ret && + ble/syntax:bash/simple-word/eval "$notilde$common_reconstructed" noglob && + local commonv_notilde=$ret && + COMPV=$compv_notilde ble/complete/candidates/filter:"$filter_type"/count-match-chars "$commonv_notilde" + then + if [[ $filter_type == head ]] && ((ret<${#COMPV})); then + is_processed=1 + [[ $bleopt_complete_allow_reduction ]] && common=$common0 + elif ((ret)); then + is_processed=1 + ble/string#escape-for-bash-specialchars "${compv_notilde:ret}" TG + common=$common0$ret + fi + fi + [[ $is_processed ]] || common=$common0$COMPS + fi + else + if ble/syntax:bash/simple-word/is-simple-or-open-simple "$common"; then + local flag_reduction= + if [[ $bleopt_complete_allow_reduction ]]; then + flag_reduction=1 + else + local simple_flags simple_ibrace + ble/syntax:bash/simple-word/reconstruct-incomplete-word "$common0" && + ble/complete/source/eval-simple-word "$ret" single && + [[ $ret == "$COMPV"* ]] && + flag_reduction=1 + (($?==148)) && return 148 + fi + [[ $flag_reduction ]] && common=$common0 + fi + fi + fi + ret=$common +} +_ble_complete_menu_active= +_ble_complete_menu_style= +_ble_complete_menu0_beg= +_ble_complete_menu0_end= +_ble_complete_menu0_str= +_ble_complete_menu_common_part= +_ble_complete_menu0_comp=() +_ble_complete_menu0_pack=() +_ble_complete_menu_comp=() +function ble/complete/menu-complete.class/render-item { + local opts=$2 + if [[ :$opts: == *:selected:* ]]; then + local COMP1=${_ble_complete_menu_comp[0]} + local COMP2=${_ble_complete_menu_comp[1]} + local COMPS=${_ble_complete_menu_comp[2]} + local COMPV=${_ble_complete_menu_comp[3]} + local comp_type=${_ble_complete_menu_comp[4]} + local comps_flags=${_ble_complete_menu0_comp[5]} + local comps_fixed=${_ble_complete_menu0_comp[6]} + local menu_common_part=$_ble_complete_menu_common_part + fi + local "${_ble_complete_cand_varnames[@]/%/=}" # WA #D1570 checked + ble/complete/cand/unpack "$1" + local prefix_len=$PREFIX_LEN + [[ :$comp_type: == *:menu-show-prefix:* ]] && prefix_len=0 + local filter_target=${CAND:prefix_len} + if [[ ! $filter_target ]]; then + ret= + return 0 + fi + local g=0 show=$filter_target suffix= prefix= + ble/function#try ble/complete/action:"$ACTION"/init-menu-item + local g0=$g; [[ :$comp_type: == *:menu-color:* ]] || g0=0 + local m + if [[ :$comp_type: == *:menu-color-match:* && $_ble_complete_menu_common_part && $show == *"$filter_target"* ]]; then + local filter_type=head + case :$comp_type: in + (*:m:*) filter_type=substr ;; + (*:a:*) filter_type=hsubseq ;; + (*:A:*) filter_type=subseq ;; + esac + local needle=${_ble_complete_menu_common_part:prefix_len} + ble/complete/candidates/filter:"$filter_type"/match "$needle" "$filter_target"; m=("${ret[@]}") + if [[ $show != "$filter_target" ]]; then + local show_prefix=${show%%"$filter_target"*} + local offset=${#show_prefix} + local i n=${#m[@]} + for ((i=0;i<n;i++)); do ((m[i]+=offset)); done + fi + else + m=() + fi + local sgrN0= sgrN1= sgrB0= sgrB1= + [[ :$opts: == *:selected:* ]] && ((g0^=_ble_color_gflags_Revert)) + ret=${_ble_color_g2sgr[g=g0]} + [[ $ret ]] || ble/color/g2sgr "$g"; sgrN0=$ret + ret=${_ble_color_g2sgr[g=g0^_ble_color_gflags_Revert]} + [[ $ret ]] || ble/color/g2sgr "$g"; sgrN1=$ret + if ((${#m[@]})); then + ret=${_ble_color_g2sgr[g=g0|_ble_color_gflags_Bold]} + [[ $ret ]] || ble/color/g2sgr "$g"; sgrB0=$ret + ret=${_ble_color_g2sgr[g=(g0|_ble_color_gflags_Bold)^_ble_color_gflags_Revert]} + [[ $ret ]] || ble/color/g2sgr "$g"; sgrB1=$ret + fi + local out= flag_overflow= p0=0 + if [[ $prefix ]]; then + ble/canvas/trace-text "$prefix" nonewline || flag_overflow=1 + out=$out$_ble_term_sgr0$ret + fi + if ((${#m[@]})); then + local i iN=${#m[@]} p p0=0 out= + for ((i=0;i<iN;i++)); do + ((p=m[i])) + if ((p0<p)); then + if ((i%2==0)); then + local sgr0=$sgrN0 sgr1=$sgrN1 + else + local sgr0=$sgrB0 sgr1=$sgrB1 + fi + ble/canvas/trace-text "${show:p0:p-p0}" nonewline:external-sgr || flag_overflow=1 + out=$out$sgr0$ret + fi + p0=$p + done + fi + if ((p0<${#show})); then + local sgr0=$sgrN0 sgr1=$sgrN1 + ble/canvas/trace-text "${show:p0}" nonewline:external-sgr || flag_overflow=1 + out=$out$sgr0$ret + fi + if [[ $suffix ]]; then + ble/canvas/trace-text "$suffix" nonewline || flag_overflow=1 + out=$out$_ble_term_sgr0$ret + fi + ret=$out$_ble_term_sgr0 + [[ ! $flag_overflow ]] +} +function ble/complete/menu-complete.class/get-desc { + local item=$1 + local "${_ble_complete_cand_varnames[@]/%/=}" # WA #D1570 checked + ble/complete/cand/unpack "$item" + desc="$desc_sgrt(action:$ACTION)$desc_sgr0" + ble/function#try ble/complete/action:"$ACTION"/get-desc +} +function ble/complete/menu-complete.class/onselect { + local nsel=$1 osel=$2 + local insert=${_ble_complete_menu_original:-${_ble_complete_menu_comp[2]}} + if ((nsel>=0)); then + local "${_ble_complete_cand_varnames[@]/%/=}" # WA #D1570 checked + ble/complete/cand/unpack "${_ble_complete_menu_items[nsel]}" + insert=$INSERT + fi + ble-edit/content/replace-limited "$_ble_complete_menu0_beg" "$_ble_edit_ind" "$insert" + ((_ble_edit_ind=_ble_complete_menu0_beg+${#insert})) +} +function ble/complete/menu/clear { + if [[ $_ble_complete_menu_active ]]; then + _ble_complete_menu_active= + ble/complete/menu#clear + [[ $_ble_highlight_layer_menu_filter_beg ]] && + ble/textarea#invalidate str # layer:menu_filter 解除 (#D0995) + fi + return 0 +} +blehook widget_bell+=ble/complete/menu/clear +blehook history_onleave+=ble/complete/menu/clear +function ble/complete/menu/get-footprint { + footprint=$_ble_edit_ind:$_ble_edit_mark_active:${_ble_edit_mark_active:+$_ble_edit_mark}:$_ble_edit_overwrite_mode:$_ble_edit_str +} +function ble/complete/menu/show { + local opts=$1 + if [[ :$opts: == *:load-filtered-data:* ]]; then + local COMP1=${_ble_complete_menu_comp[0]} + local COMP2=${_ble_complete_menu_comp[1]} + local COMPS=${_ble_complete_menu_comp[2]} + local COMPV=${_ble_complete_menu_comp[3]} + local comp_type=${_ble_complete_menu_comp[4]} + local comps_flags=${_ble_complete_menu0_comp[5]} + local comps_fixed=${_ble_complete_menu0_comp[6]} + local cand_pack; cand_pack=("${_ble_complete_menu_items[@]}") + local menu_common_part=$_ble_complete_menu_common_part + fi + local menu_style=$bleopt_complete_menu_style + [[ :$opts: == *:filter:* && $_ble_complete_menu_style ]] && + menu_style=$_ble_complete_menu_style + local menu_items; menu_items=("${cand_pack[@]}") + _ble_complete_menu_common_part=$menu_common_part + local menu_class=ble/complete/menu-complete.class menu_param= + local menu_opts=$opts + [[ :$comp_type: == *:sync:* ]] && menu_opts=$menu_opts:sync + ble/complete/menu#construct "$menu_opts" || return "$?" + ble/complete/menu#show + if [[ :$opts: == *:menu-source:* ]]; then + local left0=${_ble_complete_menu0_str::_ble_complete_menu0_end} + local left1=${_ble_edit_str::_ble_edit_ind} + local ret; ble/string#common-prefix "$left0" "$left1"; left0=$ret + local right0=${_ble_complete_menu0_str:_ble_complete_menu0_end} + local right1=${_ble_edit_str:_ble_edit_ind} + local ret; ble/string#common-suffix "$right0" "$right1"; right0=$ret + local footprint; ble/complete/menu/get-footprint + _ble_complete_menu0_str=$left0$right0 + _ble_complete_menu0_end=${#left0} + _ble_complete_menu_footprint=$footprint + elif [[ :$opts: != *:filter:* ]]; then + local beg=$COMP1 end=$_ble_edit_ind # COMP2 でなく補完挿入後の位置 + local str=$_ble_edit_str + [[ $_ble_decode_keymap == auto_complete ]] && + str=${str::_ble_edit_ind}${str:_ble_edit_mark} + local footprint; ble/complete/menu/get-footprint + _ble_complete_menu_active=1 + _ble_complete_menu_style=$menu_style + _ble_complete_menu0_beg=$beg + _ble_complete_menu0_end=$end + _ble_complete_menu0_str=$str + _ble_complete_menu0_comp=("$COMP1" "$COMP2" "$COMPS" "$COMPV" "$comp_type" "$comps_flags" "$comps_fixed") + _ble_complete_menu0_pack=("${cand_pack[@]}") + _ble_complete_menu_selected=-1 + _ble_complete_menu_comp=("$COMP1" "$COMP2" "$COMPS" "$COMPV" "$comp_type") + _ble_complete_menu_footprint=$footprint + fi + return 0 +} +function ble/complete/menu/redraw { + if [[ $_ble_complete_menu_active ]]; then + ble/complete/menu#show + fi +} +function ble/complete/menu/get-active-range { + [[ $_ble_complete_menu_active ]] || return 1 + local str=${1-$_ble_edit_str} ind=${2-$_ble_edit_ind} + local mbeg=$_ble_complete_menu0_beg + local mend=$_ble_complete_menu0_end + local left=${_ble_complete_menu0_str::mend} + local right=${_ble_complete_menu0_str:mend} + if [[ ${str::_ble_edit_ind} == "$left"* && ${str:_ble_edit_ind} == *"$right" ]]; then + ((beg=mbeg,end=${#str}-${#right})) + return 0 + else + ble/complete/menu/clear + return 1 + fi +} +function ble/complete/menu/generate-candidates-from-menu { + COMP1=${_ble_complete_menu_comp[0]} + COMP2=${_ble_complete_menu_comp[1]} + COMPS=${_ble_complete_menu_comp[2]} + COMPV=${_ble_complete_menu_comp[3]} + comp_type=${_ble_complete_menu_comp[4]} + comps_flags=${_ble_complete_menu0_comp[5]} + comps_fixed=${_ble_complete_menu0_comp[6]} + cand_count=${#_ble_complete_menu_items[@]} + cand_cand=() cand_word=() cand_pack=() + local pack "${_ble_complete_cand_varnames[@]/%/=}" # #D1570 WA checked + for pack in "${_ble_complete_menu_items[@]}"; do + ble/complete/cand/unpack "$pack" + ble/array#push cand_cand "$CAND" + ble/array#push cand_word "$INSERT" + ble/array#push cand_pack "$pack" + done + ((cand_count)) +} +function ble/complete/generate-candidates-from-opts { + local opts=$1 + local context; ble/complete/complete/determine-context-from-opts "$opts" + comp_type= + [[ :$opts: == *:auto_menu:* ]] && comp_type=auto_menu + local comp_text=$_ble_edit_str comp_index=$_ble_edit_ind + local sources + ble/complete/context:"$context"/generate-sources "$comp_text" "$comp_index" || return "$?" + ble/complete/candidates/generate "$opts" +} +function ble/complete/insert { + local insert_beg=$1 insert_end=$2 + local insert=$3 suffix=$4 + local original_text=${_ble_edit_str:insert_beg:insert_end-insert_beg} + local ret + local insert_replace= + if [[ $insert == "$original_text"* ]]; then + insert=${insert:insert_end-insert_beg} + ((insert_beg=insert_end)) + else + ble/string#common-prefix "$insert" "$original_text" + if [[ $ret ]]; then + insert=${insert:${#ret}} + ((insert_beg+=${#ret})) + fi + fi + if ble/util/test-rl-variable skip-completed-text; then + if [[ $insert ]]; then + local right_text=${_ble_edit_str:insert_end} + right_text=${right_text%%[$IFS]*} + if ble/string#common-prefix "$insert" "$right_text"; [[ $ret ]]; then + ((insert_end+=${#ret})) + elif ble/complete/string#common-suffix-prefix "$insert" "$right_text"; [[ $ret ]]; then + ((insert_end+=${#ret})) + fi + fi + if [[ $suffix ]]; then + local right_text=${_ble_edit_str:insert_end} + if ble/string#common-prefix "$suffix" "$right_text"; [[ $ret ]]; then + ((insert_end+=${#ret})) + elif ble/complete/string#common-suffix-prefix "$suffix" "$right_text"; [[ $ret ]]; then + ((insert_end+=${#ret})) + fi + fi + fi + local ins=$insert$suffix + ble/widget/.replace-range "$insert_beg" "$insert_end" "$ins" + ((_ble_edit_ind=insert_beg+${#ins}, + _ble_edit_ind>${#_ble_edit_str}&& + (_ble_edit_ind=${#_ble_edit_str}))) +} +function ble/complete/insert-common { + local ret + ble/complete/candidates/determine-common-prefix; (($?==148)) && return 148 + local insert=$ret suffix= + local insert_beg=$COMP1 insert_end=$COMP2 + local insert_flags= + [[ $insert == "$COMPS"* ]] || insert_flags=r + if ((cand_count==1)); then + local ACTION=${cand_pack[0]%%:*} + if ble/is-function ble/complete/action:"$ACTION"/complete; then + local "${_ble_complete_cand_varnames[@]/%/=}" # WA #D1570 checked + ble/complete/cand/unpack "${cand_pack[0]}" + ble/complete/action:"$ACTION"/complete + (($?==148)) && return 148 + fi + else + insert_flags=${insert_flags}m + fi + local do_insert=1 + if ((cand_count>1)) && [[ $insert_flags == *r* ]]; then + if [[ :$comp_type: != *:[maAi]:* ]]; then + do_insert= + fi + elif [[ $insert$suffix == "$COMPS" ]]; then + do_insert= + fi + if [[ $do_insert ]]; then + ble/complete/insert "$insert_beg" "$insert_end" "$insert" "$suffix" + blehook/invoke complete_insert + fi + if [[ $insert_flags == *m* ]]; then + local menu_common_part=$COMPV + local ret simple_flags simple_ibrace + if ble/syntax:bash/simple-word/reconstruct-incomplete-word "$insert"; then + ble/complete/source/eval-simple-word "$ret" single + (($?==148)) && return 148 + menu_common_part=$ret + fi + ble/complete/menu/show "$menu_show_opts" || return "$?" + elif [[ $insert_flags == *n* ]]; then + ble/widget/complete show_menu:regenerate || return "$?" + else + _ble_complete_state=complete + ble/complete/menu/clear + fi + return 0 +} +function ble/complete/insert-all { + local "${_ble_complete_cand_varnames[@]/%/=}" # WA #D1570 checked + local pack beg=$COMP1 end=$COMP2 insert= suffix= insert_flags= index=0 + for pack in "${cand_pack[@]}"; do + ble/complete/cand/unpack "$pack" + insert=$INSERT suffix= insert_flags= + if ble/is-function ble/complete/action:"$ACTION"/complete; then + ble/complete/action:"$ACTION"/complete + (($?==148)) && return 148 + fi + [[ $suffix != *' ' ]] && suffix="$suffix " + ble/complete/insert "$beg" "$end" "$insert" "$suffix" + blehook/invoke complete_insert + beg=$_ble_edit_ind end=$_ble_edit_ind + ((index++)) + done + _ble_complete_state=complete + ble/complete/menu/clear + return 0 +} +function ble/complete/insert-braces/.compose { + if ble/bin/awk.supports-null-record-separator; then + local printf_format='%s\0' RS='"\0"' + else + local printf_format='%s\x1E' RS='"\x1E"' + fi + local q=\' + local -x rex_atom='^(\\.|[0-9]+|.)' del_close= del_open= quote_type= + local -x COMPS=$COMPS + if [[ :$comp_type: != *:[maAi]:* ]]; then + local rex_brace='[,{}]|\{[-a-zA-Z0-9]+\.\.[-a-zA-Z0-9]+\}' + case $comps_flags in + (*S*) rex_atom='^('$q'(\\'$q'|'$rex_brace')'$q'|[0-9]+|.)' # '...' + del_close=\' del_open=\' quote_type=S ;; + (*E*) rex_atom='^(\\.|'$q'('$rex_brace')\$'$q'|[0-9]+|.)' # $'...' + del_close=\' del_open=\$\' quote_type=E ;; + (*[DI]*) rex_atom='^(\\[\"$`]|"('$rex_brace')"|[0-9]+|.)' # "...", $"..." + del_close=\" del_open=\" quote_type=D ;; + esac + fi + printf "$printf_format" "$@" | ble/bin/awk ' + function starts_with(str, head) { + return substr(str, 1, length(head)) == head; + } + BEGIN { + RS = '"$RS"'; + rex_atom = ENVIRON["rex_atom"]; + del_close = ENVIRON["del_close"]; + del_open = ENVIRON["del_open"]; + quote_type = ENVIRON["quote_type"]; + COMPS = ENVIRON["COMPS"]; + BRACE_OPEN = del_close "{" del_open; + BRACE_CLOS = del_close "}" del_open; + } + function to_atoms(str, arr, _, chr, atom, level, count, rex) { + count = 0; + while (match(str, rex_atom) > 0) { + chr = substr(str, 1, RLENGTH); + str = substr(str, RLENGTH + 1); + if (chr == BRACE_OPEN) { + atom = chr; + level = 1; + while (match(str, rex_atom) > 0) { + chr = substr(str, 1, RLENGTH); + str = substr(str, RLENGTH + 1); + atom = atom chr; + if (chr == BRACE_OPEN) + level++; + else if (chr == BRACE_CLOS && --level==0) + break; + } + } else { + atom = chr; + } + arr[count++] = atom; + } + return count; + } + function remove_empty_quote(str, _, rex_quote_first, rex_quote, out, empty, m) { + if (quote_type == "S" || quote_type == "E") { + rex_quote_first = "^[^'$q']*'$q'"; + rex_quote = "'$q'[^'$q']*'$q'|(\\\\.|[^'$q'])+"; + } else if (quote_type == "D") { + rex_quote_first = "^[^\"]*\""; + rex_quote = "\"([^\\\"]|\\\\.)*\"|(\\\\.|[^\"])+"; + } else return str; + empty = del_open del_close; + out = ""; + if (starts_with(str, COMPS)) { + out = COMPS; + str = substr(str, length(COMPS) + 1); + if (match(str, rex_quote_first) > 0) { + out = out substr(str, 1, RLENGTH); + str = substr(str, RLENGTH + 1); + } + } + while (match(str, rex_quote) > 0) { + m = substr(str, 1, RLENGTH); + if (m != empty) out = out m; + str = substr(str, RLENGTH + 1); + } + if (str == del_open) + return out; + else + return out str del_close; + } + function zpad(value, width, _, wpad, i, pad) { + wpad = width - length(value); + pad = ""; + for (i = 0; i < wpad; i++) pad = "0" pad; + if (value < 0) + return "-" pad (-value); + else + return pad value; + } + function zpad_remove(value) { + if (value ~ /^0+$/) + value = "0"; + else if (value ~ /^-/) + sub(/^-0+/, "-", value); + else + sub(/^0+/, "", value); + return value; + } + function zpad_a2i(text) { + sub(/^-0+/, "-", text) || sub(/^0+/, "", text); + return 0 + text; + } + function range_contract(arr, len, _, i, value, alpha, lower, upper, keys, ikey, dict, b, e, beg, end, tmp) { + lower = "abcdefghijklmnopqrstuvwxyz"; + upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + for (i = 0; i < len; i++) { + value = arr[i]; + if (dict[value]) { + dict[value]++; + } else { + keys[ikey++] = value; + dict[value] = 1; + } + } + len = 0; + for (i = 0; i < ikey; i++) { + while (dict[value = keys[i]]--) { + if (value ~ /^([a-zA-Z])$/) { + alpha = (value ~ /^[a-z]$/) ? lower : upper; + beg = end = value; + b = e = index(alpha, value); + while (b > 1 && dict[tmp = substr(alpha, b - 1, 1)]) { + dict[beg = tmp]--; + b--; + } + while (e < 26 && dict[tmp = substr(alpha, e + 1, 1)]) { + dict[end = tmp]--; + e++; + } + if (e == b) { + arr[len++] = beg; + } else if (e == b + 1) { + arr[len++] = beg; + arr[len++] = end; + } else { + arr[len++] = del_close "{" beg ".." end "}" del_open; + } + } else if (value ~ /^(0+|-?0*[1-9][0-9]*)$/) { + beg = end = value; + b = e = zpad_a2i(value); + wmax = wmin = length(value); + if (value ~ /^(0|-?[1-9][0-9]*)$/) { + while (dict[b - 1]) dict[--b]--; + while (dict[e + 1]) dict[++e]--; + tmp = length(beg = "" b); + if (tmp < wmin) wmin = tmp; + else if (tmp > wmax) wmax = tmp; + tmp = length(end = "" e); + if (tmp < wmin) wmin = tmp; + else if (tmp > wmax) wmax = tmp; + } + if (wmax == wmin) { + while (length(tmp = zpad(b - 1, wmin)) == wmin && dict[tmp]) { dict[tmp]--; --b; } + while (length(tmp = zpad(e + 1, wmin)) == wmin && dict[tmp]) { dict[tmp]--; ++e; } + beg = zpad(b, wmin); + end = zpad(e, wmin); + } + if (e == b) { + arr[len++] = beg; + } else if (e == b + 1) { + arr[len++] = beg; + arr[len++] = end; + } else if (b < 0 && e < 0) { + arr[len++] = del_close "-{" substr(end, 2) ".." substr(beg, 2) "}" del_open; + } else { + arr[len++] = del_close "{" beg ".." end "}" del_open; + } + } else { + arr[len++] = value; + } + } + } + return len; + } + function simple_brace(arr, len, _, ret, i) { + if (len == 0) return ""; + len = range_contract(arr, len); + if (len == 1) return arr[0]; + ret = BRACE_OPEN arr[0]; + for (i = 1; i < len; i++) + ret = ret del_close "," del_open arr[i]; + return ret BRACE_CLOS; + } + function rfrag_strlen_common(a, b, _, la, lb, tmp, i, n) { + ret = 0; + alen = to_atoms(a, abuf); + blen = to_atoms(b, bbuf); + while (alen > 0 && blen > 0) { + if (abuf[alen - 1] != bbuf[blen - 1]) break; + ret += length(abuf[alen - 1]); + alen--; + blen--; + } + return ret; + } + function rfrag_get_level(str, _, len, i, rfrag0, rfrag0len, rfrag1) { + len = length(str); + rfrag_matching_offset = len; + for (i = 0; i < rfrag_depth - 1; i++) { + rfrag0 = rfrag[i]; + rfrag0len = length(rfrag0); + rfrag1 = substr(str, len - rfrag0len + 1); + str = substr(str, 1, len -= rfrag0len); + if (rfrag0 != rfrag1) break; + rfrag_matching_offset -= rfrag0len; + } + while (i && rfrag[i - 1] == "") i--; # empty fragment + return i; + } + function rfrag_reduce(new_depth, _, c, i, brace, frags) { + while (rfrag_depth > new_depth) { + rfrag_depth--; + c = rfrag_count[rfrag_depth]; + for (i = 0; i < c; i++) + frags[i] = rfrag[rfrag_depth, i]; + frags[c] = rfrag[rfrag_depth]; + brace = simple_brace(frags, c + 1); + if (rfrag_depth == 0) + return brace; + else + rfrag[rfrag_depth - 1] = brace rfrag[rfrag_depth - 1]; + } + } + function rfrag_register(str, level, _, rfrag0, rfrag1, len) { + if (level == rfrag_depth) { + rfrag_depth = level + 1; + rfrag[level] = ""; + rfrag_count[level] = 0; + } else if (rfrag_depth != level + 1) { + print "ERR(rfrag)"; + } + rfrag0 = rfrag[level]; + rfrag1 = substr(str, 1, rfrag_matching_offset); + len = rfrag_strlen_common(rfrag0, rfrag1); + if (len == 0) { + rfrag[level, rfrag_count[level]++] = rfrag0; + rfrag[level] = rfrag1; + } else { + rfrag[level] = substr(rfrag0, length(rfrag0) - len + 1); + rfrag[level + 1, 0] = substr(rfrag0, 1, length(rfrag0) - len); + rfrag[level + 1] = substr(rfrag1, 1, length(rfrag1) - len); + rfrag_count[level + 1] = 1; + rfrag_depth++; + } + } + function rfrag_dump(_, i, j, prefix) { + print "depth = " rfrag_depth; + for (i = 0; i < rfrag_depth; i++) { + prefix = ""; + for (j = 0; j < i; j++) prefix = prefix " "; + for (j = 0; j < rfrag_count[i]; j++) + print prefix "rfrag[" i "," j "] = " rfrag[i,j]; + print prefix "rfrag[" i "] = " rfrag[i]; + } + } + function rfrag_brace(arr, len, _, i, level) { + if (len == 0) return ""; + if (len == 1) return arr[0]; + rfrag_depth = 1; + rfrag[0] = arr[0]; + rfrag_count[0] = 0; + for (i = 1; i < len; i++) { + level = rfrag_get_level(arr[i]); + rfrag_reduce(level + 1); + rfrag_register(arr[i], level); + } + return rfrag_reduce(0); + } + function lfrag_strlen_common(a, b, _, ret, abuf, bbuf, alen, blen, ia, ib) { + ret = 0; + alen = to_atoms(a, abuf); + blen = to_atoms(b, bbuf); + for (ia = ib = 0; ia < alen && ib < blen; ia++ + ib++) { + if (abuf[ia] != bbuf[ib]) break; + ret += length(abuf[ia]); + } + return ret; + } + function lfrag_get_level(str, _, i, frag0, frag0len, frag1) { + lfrag_matching_offset = 0; + for (i = 0; i < lfrag_depth - 1; i++) { + frag0 = frag[i] + frag0len = length(frag0); + frag1 = substr(str, lfrag_matching_offset + 1, frag0len); + if (frag0 != frag1) break; + lfrag_matching_offset += frag0len; + } + while (i && frag[i - 1] == "") i--; # empty fragment + return i; + } + function lfrag_reduce(new_depth, _, c, i, brace, frags) { + while (lfrag_depth > new_depth) { + lfrag_depth--; + c = frag_count[lfrag_depth]; + for (i = 0; i < c; i++) + frags[i] = frag[lfrag_depth, i]; + frags[c] = frag[lfrag_depth]; + brace = rfrag_brace(frags, c + 1); + if (lfrag_depth == 0) + return brace; + else + frag[lfrag_depth - 1] = frag[lfrag_depth - 1] brace; + } + } + function lfrag_register(str, level, _, frag0, frag1, len) { + if (lfrag_depth == level) { + lfrag_depth = level + 1; + frag[level] = ""; + frag_count[level] = 0; + } else if (lfrag_depth != level + 1) { + print "ERR"; + } + frag0 = frag[level]; + frag1 = substr(str, lfrag_matching_offset + 1); + len = lfrag_strlen_common(frag0, frag1); + if (len == 0) { + frag[level, frag_count[level]++] = frag0; + frag[level] = frag1; + } else { + frag[level] = substr(frag0, 1, len); + frag[level + 1, 0] = substr(frag0, len + 1); + frag[level + 1] = substr(frag1, len + 1); + frag_count[level + 1] = 1; + lfrag_depth++; + } + } + function lfrag_dump(_, i, j, prefix) { + print "depth = " lfrag_depth; + for (i = 0; i < lfrag_depth; i++) { + prefix = ""; + for (j = 0; j < i; j++) prefix = prefix " "; + for (j = 0; j < frag_count[i]; j++) + print prefix "frag[" i "," j "] = " frag[i,j]; + print prefix "frag[" i "] = " frag[i]; + } + } + NR == 1 { + lfrag_depth = 1; + frag[0] = $0; + frag_count[0] = 0; + next + } + { + level = lfrag_get_level($0); + lfrag_reduce(level + 1); + lfrag_register($0, level); + } + END { + result = lfrag_reduce(0); + result = remove_empty_quote(result); + print result; + } + ' +} +function ble/complete/insert-braces { + if ((cand_count==1)); then + ble/complete/insert-common; return "$?" + fi + local comps_len=${#COMPS} loop=0 + local -a tails=() + local common=${cand_word[0]} + ble/array#push tails "${common:comps_len}" + local word clen=${#common} + for word in "${cand_word[@]:1}"; do + ((loop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148 + ((clen>${#word}&&(clen=${#word}))) + while [[ ${word::clen} != "${common::clen}" ]]; do + ((clen--)) + done + common=${common::clen} + ble/array#push tails "${word:comps_len}" + done + local fixed=$COMPS + if [[ $common != "$COMPS"* ]]; then + tails=() + local fixed= fixval= + { + [[ $comps_fixed ]] && + fixed=${COMPS::${comps_fixed%%:*}} fixval=${comps_fixed#*:} + local ret simple_flags simple_ibrace + ble/complete/candidates/determine-common-prefix/.apply-partial-comps # var[in,out] common + if ble/syntax:bash/simple-word/reconstruct-incomplete-word "$common"; then + ble/complete/source/eval-simple-word "$ret" single + (($?==148)) && return 148 + fixed=$common fixval=$ret + fi + } + local cand ret fixval_len=${#fixval} + for cand in "${cand_cand[@]}"; do + ((loop++%bleopt_complete_polling_cycle==0)) && ble/complete/check-cancel && return 148 + [[ $cand == "$fixval"* ]] || continue + ble/complete/string#escape-for-completion-context "${cand:fixval_len}" + case $comps in + (*S*) cand=\'$ret\' ;; + (*E*) cand=\$\'$ret\' ;; + (*D*) cand=\"$ret\" ;; + (*I*) cand=\$\"$ret\" ;; + (*) cand=$ret ;; + esac + ble/array#push tails "$cand" + done + fi + local tail; ble/util/assign tail 'ble/complete/insert-braces/.compose "${tails[@]}"' + local beg=$COMP1 end=$COMP2 insert=$fixed$tail suffix= + if [[ $comps_flags == *x* ]]; then + ble/complete/action/complete.addtail ',' + else + ble/complete/action/complete.addtail ' ' + fi + ble/complete/insert "$beg" "$end" "$insert" "$suffix" + blehook/invoke complete_insert + _ble_complete_state=complete + ble/complete/menu/clear + return 0 +} +_ble_complete_state= +function ble/widget/complete { + local opts=$1 + ble-edit/content/clear-arg + local state=$_ble_complete_state + _ble_complete_state=start + local menu_show_opts= + if [[ :$opts: != *:insert_*:* && :$opts: != *:show_menu:* ]]; then + if [[ :$opts: == *:enter_menu:* ]]; then + [[ $_ble_complete_menu_active && :$opts: != *:context=*:* ]] && + ble/complete/menu-complete/enter "$opts" && return 0 + elif [[ $bleopt_complete_menu_complete ]]; then + if [[ $_ble_complete_menu_active && :$opts: != *:context=*:* ]]; then + local footprint; ble/complete/menu/get-footprint + [[ $footprint == "$_ble_complete_menu_footprint" ]] && + ble/complete/menu-complete/enter && return 0 + fi + [[ $WIDGET == "$LASTWIDGET" && $state != complete ]] && opts=$opts:enter_menu + fi + fi + local COMP1 COMP2 COMPS COMPV + local comp_type comps_flags comps_fixed + local cand_count cand_cand cand_word cand_pack + ble/complete/candidates/clear + local cand_limit_reached= + if [[ $_ble_complete_menu_active && :$opts: != *:regenerate:* && + :$opts: != *:context=*:* && ${#_ble_complete_menu_icons[@]} -gt 0 ]] + then + if [[ $_ble_complete_menu_filter_enabled && $bleopt_complete_menu_filter ]] || { + ble/complete/menu-filter; local ext=$? + ((ext==148)) && return 148 + ((ext==0)); }; then + ble/complete/menu/generate-candidates-from-menu; local ext=$? + ((ext==148)) && return 148 + if ((ext==0&&cand_count)); then + local bleopt_complete_menu_style=$_ble_complete_menu_style + menu_show_opts=$menu_show_opts:menu-source # 既存の filter 前候補を保持する + fi + fi + fi + if ((cand_count==0)); then + local bleopt_complete_menu_style=$bleopt_complete_menu_style # source 等に一次変更を認める。 + ble/complete/generate-candidates-from-opts "$opts"; local ext=$? + if ((ext==148)); then + return 148 + fi + if [[ $cand_limit_reached ]]; then + [[ :$opts: != *:no-bell:* ]] && + ble/widget/.bell 'complete: limit reached' + if [[ $cand_limit_reached == cancel ]]; then + ble/edit/info/default + return 1 + fi + fi + if ((ext!=0||cand_count==0)); then + [[ :$opts: != *:no-bell:* && ! $cand_limit_reached ]] && + ble/widget/.bell 'complete: no completions' + ble/edit/info/default + return 1 + fi + fi + if [[ :$opts: == *:insert_common:* ]]; then + ble/complete/insert-common; return "$?" + elif [[ :$opts: == *:insert_braces:* ]]; then + ble/complete/insert-braces; return "$?" + elif [[ :$opts: == *:insert_all:* ]]; then + ble/complete/insert-all; return "$?" + elif [[ :$opts: == *:enter_menu:* ]]; then + local menu_common_part=$COMPV + ble/complete/menu/show "$menu_show_opts" || return "$?" + ble/complete/menu-complete/enter "$opts"; local ext=$? + ((ext==148)) && return 148 + ((ext)) && [[ :$opts: != *:no-bell:* ]] && + ble/widget/.bell 'menu-complete: no completions' + return 0 + elif [[ :$opts: == *:show_menu:* ]]; then + local menu_common_part=$COMPV + ble/complete/menu/show "$menu_show_opts" + return "$?" # exit status of ble/complete/menu/show + fi + ble/complete/insert-common; return "$?" +} +function ble/widget/complete-insert { + local original=$1 insert=$2 suffix=$3 + [[ ${_ble_edit_str::_ble_edit_ind} == *"$original" ]] || return 1 + local insert_beg=$((_ble_edit_ind-${#original})) + local insert_end=$_ble_edit_ind + ble/complete/insert "$insert_beg" "$insert_end" "$insert" "$suffix" +} +function ble/widget/menu-complete { + local opts=$1 + ble/widget/complete enter_menu:$opts +} +function ble/complete/menu-filter/.filter-candidates { + cand_pack=() + local iloop=0 interval=$bleopt_complete_polling_cycle + local filter_type pack "${_ble_complete_cand_varnames[@]/%/=}" # #D1570 WA checked + for filter_type in head substr hsubseq subseq; do + ble/path#remove-glob comp_type '[maA]' + case $filter_type in + (substr) comp_type=${comp_type}:m ;; + (hsubseq) comp_type=${comp_type}:a ;; + (subseq) comp_type=${comp_type}:A ;; + esac + local comp_filter_type + local comp_filter_pattern + ble/complete/candidates/filter#init "$filter_type" "$COMPV" + for pack in "${_ble_complete_menu0_pack[@]}"; do + ((iloop++%interval==0)) && ble/complete/check-cancel && return 148 + ble/complete/cand/unpack "$pack" + ble/complete/candidates/filter#test "$CAND" && + ble/array#push cand_pack "$pack" + done + ((${#cand_pack[@]}!=0)) && return 0 + done +} +function ble/complete/menu-filter/.get-filter-target { + if [[ $_ble_decode_keymap == emacs || $_ble_decode_keymap == vi_[ic]map ]]; then + ret=$_ble_edit_str + elif [[ $_ble_decode_keymap == auto_complete ]]; then + ret=${_ble_edit_str::_ble_edit_ind}${_ble_edit_str:_ble_edit_mark} + else + return 1 + fi +} +function ble/complete/menu-filter { + [[ $_ble_decode_keymap == menu_complete ]] && return 0 + local ret; ble/complete/menu-filter/.get-filter-target || return 1; local str=$ret + local beg end; ble/complete/menu/get-active-range "$str" "$_ble_edit_ind" || return 1 + local input=${str:beg:end-beg} + [[ $input == "${_ble_complete_menu_comp[2]}" ]] && return 0 + local simple_flags simple_ibrace + if ! ble/syntax:bash/simple-word/reconstruct-incomplete-word "$input"; then + ble/syntax:bash/simple-word/is-never-word "$input" && return 1 + return 0 + fi + [[ $simple_ibrace ]] && ((${simple_ibrace%%:*}>10#0${_ble_complete_menu0_comp[6]%%:*})) && return 1 # 別のブレース展開要素に入った時 + ble/syntax:bash/simple-word/eval "$ret" single; (($?==148)) && return 148 + local COMPV=$ret + local comp_type=${_ble_complete_menu0_comp[4]} cand_pack + ble/complete/menu-filter/.filter-candidates; (($?==148)) && return 148 + local menu_common_part=$COMPV + ble/complete/menu/show filter || return "$?" + _ble_complete_menu_comp=("$beg" "$end" "$input" "$COMPV" "$comp_type") + return 0 +} +function ble/complete/menu-filter.idle { + ble/util/idle.wait-user-input + [[ $bleopt_complete_menu_filter ]] || return 1 + [[ $_ble_complete_menu_active ]] || return 1 + ble/complete/menu-filter; local ext=$? + ((ext==148)) && return 148 + ((ext)) && ble/complete/menu/clear + return 0 +} +function ble/highlight/layer/buff#operate-gflags { + local BUFF=$1 beg=$2 end=$3 mask=$4 gflags=$5 + ((beg<end)) || return 1 + if [[ $mask == auto ]]; then + mask=0 + ((gflags&(_ble_color_gflags_FgIndexed|_ble_color_gflags_FgMask))) && + ((mask|=_ble_color_gflags_FgIndexed|_ble_color_gflags_FgMask)) + ((gflags&(_ble_color_gflags_BgIndexed|_ble_color_gflags_BgMask))) && + ((mask|=_ble_color_gflags_BgIndexed|_ble_color_gflags_BgMask)) + fi + local i g ret + for ((i=beg;i<end;i++)); do + ble/highlight/layer/update/getg "$i" + ((g=g&~mask|gflags)) + ble/color/g2sgr "$g" + builtin eval -- "$BUFF[$i]=\$ret\${_ble_highlight_layer_plain_buff[$i]}" + done +} +function ble/highlight/layer/buff#set-explicit-sgr { + local BUFF=$1 index=$2 + builtin eval "((index<\${#$BUFF[@]}))" || return 1 + local g; ble/highlight/layer/update/getg "$index" + local ret; ble/color/g2sgr "$g" + builtin eval "$BUFF[index]=\$ret\${_ble_highlight_layer_plain_buff[index]}" +} +ble/color/defface menu_filter_fixed bold +ble/color/defface menu_filter_input fg=16,bg=229 +_ble_highlight_layer_menu_filter_buff=() +_ble_highlight_layer_menu_filter_beg= +_ble_highlight_layer_menu_filter_end= +function ble/highlight/layer:menu_filter/update { + local text=$1 player=$2 + local obeg=$_ble_highlight_layer_menu_filter_beg + local oend=$_ble_highlight_layer_menu_filter_end + if [[ $obeg ]] && ((DMIN>=0)); then + ((DMAX0<=obeg?(obeg+=DMAX-DMAX0):(DMIN<obeg&&(obeg=DMIN)), + DMAX0<=oend?(oend+=DMAX-DMAX0):(DMIN<oend&&(oend=DMIN)))) + fi + _ble_highlight_layer_menu_filter_beg=$obeg + _ble_highlight_layer_menu_filter_end=$oend + local beg= end= ret + if [[ $bleopt_complete_menu_filter && $_ble_complete_menu_active && ${#_ble_complete_menu_icons[@]} -gt 0 ]]; then + ble/complete/menu-filter/.get-filter-target && local str=$ret && + ble/complete/menu/get-active-range "$str" "$_ble_edit_ind" && + [[ ${str:beg:end-beg} != "${_ble_complete_menu0_comp[2]}" ]] || beg= end= + fi + [[ ! $obeg && ! $beg ]] && return 0 + ((PREV_UMIN<0)) && [[ $beg == "$obeg" && $end == "$oend" ]] && + PREV_BUFF=_ble_highlight_layer_menu_filter_buff && return 0 + local umin=$PREV_UMIN umax=$PREV_UMAX + if [[ $beg ]]; then + ble/color/face2g menu_filter_fixed; local gF=$ret + ble/color/face2g menu_filter_input; local gI=$ret + local mid=$_ble_complete_menu0_end + ((mid<beg?(mid=beg):(end<mid&&(mid=end)))) + local buff_name=_ble_highlight_layer_menu_filter_buff + builtin eval "$buff_name=(\"\${$PREV_BUFF[@]}\")" + ble/highlight/layer/buff#operate-gflags "$buff_name" "$beg" "$mid" auto "$gF" + ble/highlight/layer/buff#operate-gflags "$buff_name" "$mid" "$end" auto "$gI" + ble/highlight/layer/buff#set-explicit-sgr "$buff_name" "$end" + PREV_BUFF=$buff_name + if [[ $obeg ]]; then : + ble/highlight/layer:region/.update-dirty-range "$beg" "$obeg" + ble/highlight/layer:region/.update-dirty-range "$end" "$oend" + else + ble/highlight/layer:region/.update-dirty-range "$beg" "$end" + fi + else + if [[ $obeg ]]; then + ble/highlight/layer:region/.update-dirty-range "$obeg" "$oend" + fi + fi + _ble_highlight_layer_menu_filter_beg=$beg + _ble_highlight_layer_menu_filter_end=$end + ((PREV_UMIN=umin,PREV_UMAX=umax)) +} +function ble/highlight/layer:menu_filter/getg { + local index=$1 + local obeg=$_ble_highlight_layer_menu_filter_beg + local oend=$_ble_highlight_layer_menu_filter_end + local mid=$_ble_complete_menu0_end + if [[ $obeg ]] && ((obeg<=index&&index<oend)); then + local ret + if ((index<mid)); then + ble/color/face2g menu_filter_fixed; local g0=$ret + else + ble/color/face2g menu_filter_input; local g0=$ret + fi + ble/highlight/layer/update/getg "$index" + ble/color/g.append "$g0" + fi +} +_ble_complete_menu_filter_enabled= +if ble/is-function ble/util/idle.push-background; then + _ble_complete_menu_filter_enabled=1 + ble/util/idle.push -n 9999 ble/complete/menu-filter.idle + ble/array#insert-before _ble_highlight_layer__list region menu_filter +fi +_ble_complete_menu_original= +function ble/complete/menu-complete/select { + ble/complete/menu#select "$@" +} +function ble/complete/menu-complete/enter { + ((${#_ble_complete_menu_icons[@]}>=1)) || return 1 + local beg end; ble/complete/menu/get-active-range || return 1 + local opts=$1 + _ble_edit_mark=$beg + _ble_edit_ind=$end + local comps_fixed=${_ble_complete_menu0_comp[6]} + if [[ $comps_fixed ]]; then + local comps_fixed_length=${comps_fixed%%:*} + ((_ble_edit_mark+=comps_fixed_length)) + fi + _ble_complete_menu_original=${_ble_edit_str:beg:end-beg} + ble/complete/menu/redraw + if [[ :$opts: == *:backward:* ]]; then + ble/complete/menu#select $((${#_ble_complete_menu_items[@]}-1)) + else + ble/complete/menu#select 0 + fi + _ble_edit_mark_active=insert + ble/decode/keymap/push menu_complete + return 0 +} +function ble/widget/menu_complete/exit { + local opts=$1 + ble/decode/keymap/pop + if ((_ble_complete_menu_selected>=0)); then + local new=${_ble_edit_str:_ble_complete_menu0_beg:_ble_edit_ind-_ble_complete_menu0_beg} + local old=$_ble_complete_menu_original + local comp_text=${_ble_edit_str::_ble_complete_menu0_beg}$old${_ble_edit_str:_ble_edit_ind} + local insert_beg=$_ble_complete_menu0_beg + local insert_end=$((_ble_complete_menu0_beg+${#old})) + local insert=$new + local insert_flags= + local suffix= + if [[ :$opts: == *:complete:* ]]; then + local icon=${_ble_complete_menu_icons[_ble_complete_menu_selected-_ble_complete_menu_offset]} + local icon_data=${icon#*:} icon_fields + ble/string#split icon_fields , "${icon%%:*}" + local pack=${icon_data::icon_fields[4]} + local ACTION=${pack%%:*} + if ble/is-function ble/complete/action:"$ACTION"/complete; then + local COMP1=${_ble_complete_menu0_comp[0]} + local COMP2=${_ble_complete_menu0_comp[1]} + local COMPS=${_ble_complete_menu0_comp[2]} + local COMPV=${_ble_complete_menu0_comp[3]} + local comp_type=${_ble_complete_menu0_comp[4]} + local comps_flags=${_ble_complete_menu0_comp[5]} + local comps_fixed=${_ble_complete_menu0_comp[6]} + local "${_ble_complete_cand_varnames[@]/%/=}" # WA #D1570 checked + ble/complete/cand/unpack "$pack" + ble/complete/action:"$ACTION"/complete + fi + ble/complete/insert "$_ble_complete_menu0_beg" "$_ble_edit_ind" "$insert" "$suffix" + fi + blehook/invoke complete_insert + fi + ble/complete/menu/clear + _ble_edit_mark_active= + _ble_complete_menu_original= +} +function ble/widget/menu_complete/cancel { + ble/decode/keymap/pop + ble/complete/menu#select -1 + _ble_edit_mark_active= + _ble_complete_menu_original= +} +function ble/widget/menu_complete/accept { + ble/widget/menu_complete/exit complete +} +function ble/widget/menu_complete/exit-default { + ble/widget/menu_complete/exit + ble/decode/widget/skip-lastwidget + ble/decode/widget/redispatch-by-keys "${KEYS[@]}" +} +function ble-decode/keymap:menu_complete/define { + ble-bind -f __default__ 'menu_complete/exit-default' + ble-bind -f __line_limit__ nop + ble-bind -f C-m 'menu_complete/accept' + ble-bind -f RET 'menu_complete/accept' + ble-bind -f C-g 'menu_complete/cancel' + ble-bind -f 'C-x C-g' 'menu_complete/cancel' + ble-bind -f 'C-M-g' 'menu_complete/cancel' + ble-bind -f C-f 'menu/forward-column' + ble-bind -f right 'menu/forward-column' + ble-bind -f C-i 'menu/forward cyclic' + ble-bind -f TAB 'menu/forward cyclic' + ble-bind -f C-b 'menu/backward-column' + ble-bind -f left 'menu/backward-column' + ble-bind -f C-S-i 'menu/backward cyclic' + ble-bind -f S-TAB 'menu/backward cyclic' + ble-bind -f C-n 'menu/forward-line' + ble-bind -f down 'menu/forward-line' + ble-bind -f C-p 'menu/backward-line' + ble-bind -f up 'menu/backward-line' + ble-bind -f prior 'menu/backward-page' + ble-bind -f next 'menu/forward-page' + ble-bind -f home 'menu/beginning-of-page' + ble-bind -f end 'menu/end-of-page' +} +function ble/complete/auto-complete/initialize { + local ret + ble-decode-kbd/generate-keycode auto_complete_enter + _ble_complete_KCODE_ENTER=$ret +} +ble/complete/auto-complete/initialize +function ble/highlight/layer:region/mark:auto_complete/get-face { + face=auto_complete +} +_ble_complete_ac_type= +_ble_complete_ac_comp1= +_ble_complete_ac_cand= +_ble_complete_ac_word= +_ble_complete_ac_insert= +_ble_complete_ac_suffix= +function ble/complete/auto-complete/.search-history-light { + [[ $_ble_history_prefix ]] && return 1 + local text=$1 + [[ ! $text ]] && return 1 + local wordbreaks="<>();&|:$_ble_term_IFS" + local word= expand + if [[ $text != [-0-9#?!]* ]]; then + word=${text%%[$wordbreaks]*} + command='!'$word ble/util/assign expand 'ble/edit/hist_expanded/.core' &>/dev/null || return 1 + if [[ $expand == "$text"* ]]; then + ret=$expand + return 0 + fi + fi + if [[ $word != "$text" ]]; then + local fragments; ble/string#split fragments '?' "$text" + local frag longest_fragments len=0; longest_fragments=('') + for frag in "${fragments[@]}"; do + local len1=${#frag} + ((len1>len&&(len=len1))) && longest_fragments=() + ((len1==len)) && ble/array#push longest_fragments "$frag" + done + for frag in "${longest_fragments[@]}"; do + command='!?'$frag ble/util/assign expand 'ble/edit/hist_expanded/.core' &>/dev/null || return 1 + [[ $expand == "$text"* ]] || continue + ret=$expand + return 0 + done + fi + return 1 +} +_ble_complete_ac_history_needle= +_ble_complete_ac_history_index= +_ble_complete_ac_history_start= +function ble/complete/auto-complete/.search-history-heavy { + local text=$1 + local count; ble/history/get-count -v count + local start=$((count-1)) + local index=$((count-1)) + local needle=$text + ((start==_ble_complete_ac_history_start)) && + [[ $needle == "$_ble_complete_ac_history_needle"* ]] && + index=$_ble_complete_ac_history_index + local isearch_time=0 isearch_ntask=1 + local isearch_opts=head + [[ :$comp_type: == *:sync:* ]] || isearch_opts=$isearch_opts:stop_check + ble/history/isearch-backward-blockwise "$isearch_opts"; local ext=$? + _ble_complete_ac_history_start=$start + _ble_complete_ac_history_index=$index + _ble_complete_ac_history_needle=$needle + ((ext)) && return "$ext" + ble/history/get-edited-entry -v ret "$index" + return 0 +} +function ble/complete/auto-complete/.enter-auto-complete-mode { + _ble_complete_ac_type=$type + _ble_complete_ac_comp1=$COMP1 + _ble_complete_ac_cand=$cand + _ble_complete_ac_word=$word + _ble_complete_ac_insert=$insert + _ble_complete_ac_suffix=$suffix + _ble_edit_mark_active=auto_complete + ble/decode/keymap/push auto_complete + ble-decode-key "$_ble_complete_KCODE_ENTER" # dummy key input to record keyboard macros +} +function ble/complete/auto-complete/.insert { + local insert=$1 + ble-edit/content/replace-limited "$_ble_edit_ind" "$_ble_edit_ind" "$insert" nobell + ((_ble_edit_mark=_ble_edit_ind+${#insert})) +} +function ble/complete/auto-complete/.check-history { + local opts=$1 + local searcher=.search-history-heavy + [[ :$opts: == *:light:* ]] && searcher=.search-history-light + local ret + ((_ble_edit_ind==${#_ble_edit_str})) || return 1 + ble/complete/auto-complete/"$searcher" "$_ble_edit_str" || return "$?" # 0, 1 or 148 + local word=$ret cand= + local COMP1=0 COMPS=$_ble_edit_str + [[ $word == "$COMPS" ]] && return 1 + local insert=$word suffix= + local type=h + ble/complete/auto-complete/.insert "${insert:${#COMPS}}" + ble/complete/auto-complete/.enter-auto-complete-mode + return 0 +} +function ble/complete/auto-complete/.check-context { + local sources + ble/complete/context:syntax/generate-sources "$comp_text" "$comp_index" && + ble/complete/context/filter-prefix-sources || return 1 + local bleopt_complete_contract_function_names= + local bleopt_complete_menu_style=$bleopt_complete_menu_style # source local settings + ((bleopt_complete_polling_cycle>25)) && + local bleopt_complete_polling_cycle=25 + local COMP1 COMP2 COMPS COMPV + local comps_flags comps_fixed + local cand_count cand_cand cand_word cand_pack + local cand_limit_reached= + ble/complete/candidates/generate; local ext=$? + [[ $COMPV ]] || return 1 + ((ext)) && return "$ext" + ((cand_count)) || return 1 + local word=${cand_word[0]} cand=${cand_cand[0]} + [[ $word == "$COMPS" ]] && return 1 + local insert=$word suffix= + local ACTION=${cand_pack[0]%%:*} + if ble/is-function ble/complete/action:"$ACTION"/complete; then + local "${_ble_complete_cand_varnames[@]/%/=}" # WA #D1570 checked + ble/complete/cand/unpack "${cand_pack[0]}" + ble/complete/action:"$ACTION"/complete + fi + local type= + if [[ $insert == "$COMPS"* ]]; then + [[ ${comp_text:COMP1} == "$insert"* ]] && return 1 + type=c + ble/complete/auto-complete/.insert "${insert:${#COMPS}}" + else + case :$comp_type: in + (*:a:*) type=a ;; + (*:m:*) type=m ;; + (*:A:*) type=A ;; + (*) type=r ;; + esac + ble/complete/auto-complete/.insert " [$insert] " + fi + ble/complete/auto-complete/.enter-auto-complete-mode + return 0 +} +function ble/complete/auto-complete.impl { + local opts=$1 + local comp_type=auto + [[ :$opts: == *:sync:* ]] && comp_type=${comp_type}:sync + local comp_text=$_ble_edit_str comp_index=$_ble_edit_ind + [[ $comp_text ]] || return 0 + if local beg end; ble/complete/menu/get-active-range "$_ble_edit_str" "$_ble_edit_ind"; then + ((_ble_edit_ind<end)) && return 0 + fi + if [[ $bleopt_complete_auto_history ]]; then + ble/complete/auto-complete/.check-history light; local ext=$? + ((ext==0||ext==148)) && return "$ext" + [[ $_ble_history_prefix || $_ble_history_load_done ]] && + ble/complete/auto-complete/.check-history; local ext=$? + ((ext==0||ext==148)) && return "$ext" + fi + ble/complete/auto-complete/.check-context +} +function ble/complete/auto-complete.idle { + ble/util/idle.wait-user-input + [[ $bleopt_complete_auto_complete ]] || return 1 + [[ $_ble_decode_keymap == emacs || $_ble_decode_keymap == vi_[ic]map ]] || return 0 + case $_ble_decode_widget_last in + (ble/widget/self-insert) ;; + (ble/widget/complete) ;; + (ble/widget/vi_imap/complete) ;; + (*) return 0 ;; + esac + [[ $_ble_edit_str ]] || return 0 + ble/util/idle.sleep-until $((_idle_clock_start+bleopt_complete_auto_delay)) checked && return 0 + ble/complete/auto-complete.impl +} +function ble/complete/auto-menu.idle { + ble/util/idle.wait-user-input + [[ $_ble_complete_menu_active ]] && return 0 + ((bleopt_complete_auto_menu>0)) || return 1 + case $_ble_decode_widget_last in + (ble/widget/self-insert) ;; + (ble/widget/complete) ;; + (ble/widget/vi_imap/complete) ;; + (ble/widget/auto_complete/self-insert) ;; + (*) return 0 ;; + esac + [[ $_ble_edit_str ]] || return 0 + local until=$((_idle_clock_start+bleopt_complete_auto_menu)) + ble/util/idle.sleep-until "$until" checked && return 0 + ble/widget/complete auto_menu:show_menu:no-empty:no-bell +} +ble/function#try ble/util/idle.push-background ble/complete/auto-complete.idle +ble/function#try ble/util/idle.push-background ble/complete/auto-menu.idle +function ble/widget/auto-complete-enter { + ble/complete/auto-complete.impl sync +} +function ble/widget/auto_complete/cancel { + ble/decode/keymap/pop + ble-edit/content/replace "$_ble_edit_ind" "$_ble_edit_mark" '' + _ble_edit_mark=$_ble_edit_ind + _ble_edit_mark_active= + _ble_complete_ac_insert= + _ble_complete_ac_suffix= +} +function ble/widget/auto_complete/insert { + ble/decode/keymap/pop + ble-edit/content/replace "$_ble_edit_ind" "$_ble_edit_mark" '' + _ble_edit_mark=$_ble_edit_ind + local comp_text=$_ble_edit_str + local insert_beg=$_ble_complete_ac_comp1 + local insert_end=$_ble_edit_ind + local insert=$_ble_complete_ac_insert + local suffix=$_ble_complete_ac_suffix + ble/complete/insert "$insert_beg" "$insert_end" "$insert" "$suffix" + blehook/invoke complete_insert + _ble_edit_mark_active= + _ble_complete_ac_insert= + _ble_complete_ac_suffix= + ble/complete/menu/clear + ble-edit/content/clear-arg + return 0 +} +function ble/widget/auto_complete/cancel-default { + ble/widget/auto_complete/cancel + ble/decode/widget/skip-lastwidget + ble/decode/widget/redispatch-by-keys "${KEYS[@]}" +} +function ble/widget/auto_complete/self-insert { + local code; ble/widget/self-insert/.get-code + ((code==0)) && return 0 + local ret + ble/util/c2s "$code"; local ins=$ret + local comps_cur=${_ble_edit_str:_ble_complete_ac_comp1:_ble_edit_ind-_ble_complete_ac_comp1} + local comps_new=$comps_cur$ins + local processed= + if [[ $_ble_complete_ac_type == [ch] ]]; then + if [[ $_ble_complete_ac_word == "$comps_new"* ]]; then + ((_ble_edit_ind+=${#ins})) + [[ ! $_ble_complete_ac_word ]] && ble/widget/auto_complete/cancel + processed=1 + fi + elif [[ $_ble_complete_ac_type == [rmaA] && $ins != [{,}] ]]; then + if local ret simple_flags simple_ibrace; ble/syntax:bash/simple-word/reconstruct-incomplete-word "$comps_new"; then + if ble/complete/source/eval-simple-word "$ret" single && local compv_new=$ret; then + local filter_type=head + case $_ble_complete_ac_type in + (*m*) filter_type=substr ;; + (*a*) filter_type=hsubseq ;; + (*A*) filter_type=subseq ;; + esac + local comps_fixed= + local comp_filter_type + local comp_filter_pattern + ble/complete/candidates/filter#init "$filter_type" "$compv_new" + if ble/complete/candidates/filter#test "$_ble_complete_ac_cand"; then + local insert; ble-edit/content/replace-limited "$_ble_edit_ind" "$_ble_edit_ind" "$ins" + ((_ble_edit_ind+=${#insert},_ble_edit_mark+=${#insert})) + [[ $_ble_complete_ac_cand == "$compv_new" ]] && + ble/widget/auto_complete/cancel + processed=1 + fi + fi + fi + fi + if [[ $processed ]]; then + local comp_text= insert_beg=0 insert_end=0 insert=$ins suffix= + blehook/invoke complete_insert + return 0 + else + ble/widget/auto_complete/cancel + ble/decode/widget/skip-lastwidget + ble/decode/widget/redispatch-by-keys "${KEYS[@]}" + fi +} +function ble/widget/auto_complete/insert-on-end { + if ((_ble_edit_mark==${#_ble_edit_str})); then + ble/widget/auto_complete/insert + else + ble/widget/auto_complete/cancel-default + fi +} +function ble/widget/auto_complete/insert-word { + local breaks=${bleopt_complete_auto_wordbreaks:-$_ble_term_IFS} + local rex='^['$breaks']*([^'$breaks']+['$breaks']*)?' + if [[ $_ble_complete_ac_type == [ch] ]]; then + local ins=${_ble_edit_str:_ble_edit_ind:_ble_edit_mark-_ble_edit_ind} + [[ $ins =~ $rex ]] + if [[ $BASH_REMATCH == "$ins" ]]; then + ble/widget/auto_complete/insert + return 0 + else + local ins=$BASH_REMATCH + ((_ble_edit_ind+=${#ins})) + local comp_text=$_ble_edit_str + local insert_beg=$_ble_complete_ac_comp1 + local insert_end=$_ble_edit_ind + local insert=${_ble_edit_str:insert_beg:insert_end-insert_beg}$ins + local suffix= + blehook/invoke complete_insert + return 0 + fi + elif [[ $_ble_complete_ac_type == [rmaA] ]]; then + local ins=$_ble_complete_ac_insert + [[ $ins =~ $rex ]] + if [[ $BASH_REMATCH == "$ins" ]]; then + ble/widget/auto_complete/insert + return 0 + else + local ins=$BASH_REMATCH + _ble_complete_ac_type=c + ble-edit/content/replace "$_ble_complete_ac_comp1" "$_ble_edit_mark" "$_ble_complete_ac_insert" + ((_ble_edit_ind=_ble_complete_ac_comp1+${#ins}, + _ble_edit_mark=_ble_complete_ac_comp1+${#_ble_complete_ac_insert})) + local comp_text=$_ble_edit_str + local insert_beg=$_ble_complete_ac_comp1 + local insert_end=$_ble_edit_ind + local insert=$ins + local suffix= + blehook/invoke complete_insert + return 0 + fi + fi + return 1 +} +function ble/widget/auto_complete/accept-line { + ble/widget/auto_complete/insert + ble-decode-key 13 +} +function ble/widget/auto_complete/notify-enter { + ble/decode/widget/skip-lastwidget +} +function ble-decode/keymap:auto_complete/define { + ble-bind -f __defchar__ auto_complete/self-insert + ble-bind -f __default__ auto_complete/cancel-default + ble-bind -f __line_limit__ nop + ble-bind -f 'C-g' auto_complete/cancel + ble-bind -f 'C-x C-g' auto_complete/cancel + ble-bind -f 'C-M-g' auto_complete/cancel + ble-bind -f S-RET auto_complete/insert + ble-bind -f S-C-m auto_complete/insert + ble-bind -f C-f auto_complete/insert-on-end + ble-bind -f right auto_complete/insert-on-end + ble-bind -f C-e auto_complete/insert-on-end + ble-bind -f end auto_complete/insert-on-end + ble-bind -f M-f auto_complete/insert-word + ble-bind -f M-right auto_complete/insert-word + ble-bind -f C-j auto_complete/accept-line + ble-bind -f C-RET auto_complete/accept-line + ble-bind -f auto_complete_enter auto_complete/notify-enter +} +function ble/complete/sabbrev/.initialize-print { + sgr0= sgr1= sgr2= sgr3= sgro= + if [[ $flags == *c* || $flags != *n* && -t 1 ]]; then + local ret + ble/color/face2sgr command_function; sgr1=$ret + ble/color/face2sgr syntax_varname; sgr2=$ret + ble/color/face2sgr syntax_quoted; sgr3=$ret + ble/color/face2sgr argument_option; sgro=$ret + sgr0=$_ble_term_sgr0 + fi +} +function ble/complete/sabbrev/.print-definition { + local key=$1 type=${2%%:*} value=${2#*:} + local option= + [[ $type == m ]] && option=$sgro'-m'$sgr0' ' + local ret + ble/string#quote-word "$key" quote-empty:sgrq="$sgr3":sgr0="$sgr2" + key=$sgr2$ret$sgr0 + ble/string#quote-word "$value" sgrq="$sgr3":sgr0="$sgr0" + value=$ret + ble/util/print "${sgr1}ble-sabbrev$sgr0 $option$key=$value" +} +function ble/complete/sabbrev/register { + local key=$1 value=$2 + ble/gdict#set _ble_complete_sabbrev "$key" "$value" +} +function ble/complete/sabbrev/list { + local keys ret; keys=("$@") + if ((${#keys[@]}==0)); then + ble/gdict#keys _ble_complete_sabbrev + keys=("${ret[@]}") + ((${#keys[@]})) || return 0 + fi + local sgr0 sgr1 sgr2 sgr3 sgro + ble/complete/sabbrev/.initialize-print + local key ext=0 + for key in "${keys[@]}"; do + if ble/gdict#get _ble_complete_sabbrev "$key"; then + ble/complete/sabbrev/.print-definition "$key" "$ret" + else + ble/util/print "ble-sabbrev: $key: not found." >&2 + ext=1 + fi + done + return "$ext" +} +function ble/complete/sabbrev/reset { + if (($#)); then + local key + for key; do + ble/gdict#unset _ble_complete_sabbrev "$key" + done + else + ble/gdict#clear _ble_complete_sabbrev + fi + return 0 +} +function ble/complete/sabbrev/get { + local key=$1 + ble/gdict#get _ble_complete_sabbrev "$key" +} +function ble/complete/sabbrev/get-keys { + local ret + ble/gdict#keys _ble_complete_sabbrev + keys=("${ret[@]}") +} +function ble/complete/sabbrev/read-arguments { + while (($#)); do + local arg=$1; shift + if [[ $arg == ?*=* ]]; then + ble/array#push specs "s:$arg" + else + case $arg in + (--help) + flags=H$flags ;; + (--reset) + flags=r$flags + (--color|--color=always) + flags=c${flags//[cn]} ;; + (--color=never) + flags=n${flags//[cn]} ;; + (--color=auto) + flags=${flags//[cn]} ;; + (-*) + local i n=${#arg} c + for ((i=1;i<n;i++)); do + c=${arg:i:1} + case $c in + (m) + if ((!$#)); then + ble/util/print "ble-sabbrev: option argument for '-$c' is missing" >&2 + flags=E$flags + elif [[ $1 != ?*=* ]]; then + ble/util/print "ble-sabbrev: invalid option argument '-$c $1' (expected form: '-$c key=value')" >&2 + flags=E$flags + else + ble/array#push specs "$c:$1"; shift + fi ;; + (r) + flags=r$flags ;; + (*) + ble/util/print "ble-sabbrev: unknown option '-$c'." >&2 + flags=E$flags ;; + esac + done ;; + (*) + ble/array#push print "$arg" ;; + esac + fi + done +} +function ble-sabbrev { + local -a specs=() print=() + local flags= + ble/complete/sabbrev/read-arguments "$@" + if [[ $flags == *H* || $flags == *E* ]]; then + [[ $flags == *E* ]] && ble/util/print + ble/util/print-lines \ + 'usage: ble-sabbrev [KEY=VALUE|-m KEY=FUNCTION]...' \ + 'usage: ble-sabbrev [-r|--reset] [KEY...]' \ + 'usage: ble-sabbrev --help' \ + ' Register sabbrev expansion.' + [[ ! $flags == *E* ]]; return "$?" + fi + local ext=0 + if ((${#specs[@]}==0||${#print[@]})); then + if [[ $flags == *r* ]]; then + ble/complete/sabbrev/reset "${print[@]}" + else + ble/complete/sabbrev/list "${print[@]}" + fi || ext=$? + fi + local spec key type value + for spec in "${specs[@]}"; do + type=${spec::1} spec=${spec:2} + key=${spec%%=*} value=${spec#*=} + ble/complete/sabbrev/register "$key" "$type:$value" + done + return "$ext" +} +function ble/complete/sabbrev/expand { + local sources comp_index=$_ble_edit_ind comp_text=$_ble_edit_str + ble/complete/context:syntax/generate-sources + local src asrc pos=$comp_index + for src in "${sources[@]}"; do + ble/string#split-words asrc "$src" + case ${asrc[0]} in + (file|command|argument|variable:w|wordlist:*|sabbrev) + ((asrc[1]<pos)) && pos=${asrc[1]} ;; + esac + done + ((pos<comp_index)) || return 1 + local key=${_ble_edit_str:pos:comp_index-pos} + local ret; ble/complete/sabbrev/get "$key" || return 1 + local type=${ret%%:*} value=${ret#*:} + case $type in + (s) + ble/widget/.replace-range "$pos" "$comp_index" "$value" + ((_ble_edit_ind=pos+${#value})) ;; + (m) + local comp_type= comps_flags= comps_fixed= + local COMP1=$pos COMP2=$pos COMPS=$key COMPV= + ble/complete/candidates/comp_type#read-rl-variables + local flag_force_fignore= + local flag_source_filter=1 + local cand_count cand_cand cand_word cand_pack + ble/complete/candidates/clear + local COMP_PREFIX= + local bleopt_sabbrev_menu_style=$bleopt_complete_menu_style + local bleopt_sabbrev_menu_opts= + local -a COMPREPLY=() + builtin eval -- "$value" + local cand action=word "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe + ble/complete/cand/yield.initialize "$action" + for cand in "${COMPREPLY[@]}"; do + ble/complete/cand/yield "$action" "$cand" "" + done + if ((cand_count==0)); then + return 1 + elif ((cand_count==1)); then + local value=${cand_word[0]} + ble/widget/.replace-range "$pos" "$comp_index" "$value" + ((_ble_edit_ind=pos+${#value})) + return 0 + fi + ble/widget/.replace-range "$pos" "$comp_index" '' + local bleopt_complete_menu_style=$bleopt_sabbrev_menu_style + local menu_common_part= + ble/complete/menu/show || return "$?" + [[ :$bleopt_sabbrev_menu_opts: == *:enter_menu:* ]] && + ble/complete/menu-complete/enter + return 147 ;; + (*) return 1 ;; + esac + return 0 +} +function ble/widget/sabbrev-expand { + if ! ble/complete/sabbrev/expand; then + ble/widget/.bell + return 1 + fi +} +function ble/complete/action:sabbrev/initialize { CAND=$value; } +function ble/complete/action:sabbrev/complete { :; } +function ble/complete/action:sabbrev/init-menu-item { + local ret; ble/color/face2g command_alias; g=$ret + show=$INSERT +} +function ble/complete/action:sabbrev/get-desc { + local ret; ble/complete/sabbrev/get "$INSERT" + desc="$desc_sgrt(sabbrev)$desc_sgr0 $ret" +} +function ble/complete/source:sabbrev { + local keys; ble/complete/sabbrev/get-keys + local filter_type=$comp_filter_type + [[ $filter_type == none ]] && filter_type=head + local comps_fixed= + local comp_filter_type + local comp_filter_pattern + ble/complete/candidates/filter#init "$filter_type" "$COMPS" + local cand action=sabbrev "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe + ble/complete/cand/yield.initialize "$action" + for cand in "${keys[@]}"; do + ble/complete/candidates/filter#test "$cand" || continue + local ret simple_flags simple_ibrace + ble/syntax:bash/simple-word/reconstruct-incomplete-word "$cand" && + ble/complete/source/eval-simple-word "$ret" single || continue + local value=$ret # referenced in "ble/complete/action:sabbrev/initialize" + local flag_source_filter=1 + ble/complete/cand/yield "$action" "$cand" + done +} +_ble_complete_dabbrev_original= +_ble_complete_dabbrev_regex1= +_ble_complete_dabbrev_regex2= +_ble_complete_dabbrev_index= +_ble_complete_dabbrev_pos= +_ble_complete_dabbrev_stack=() +function ble/complete/dabbrev/.show-status.fib { + local index='!'$((_ble_complete_dabbrev_index+1)) + local nmatch=${#_ble_complete_dabbrev_stack[@]} + local needle=$_ble_complete_dabbrev_original + local text="(dabbrev#$nmatch: << $index) \`$needle'" + local pos=$1 + if [[ $pos ]]; then + local count; ble/history/get-count + local percentage=$((count?pos*1000/count:1000)) + text="$text searching... @$pos ($((percentage/10)).$((percentage%10))%)" + fi + ((fib_ntask)) && text="$text *$fib_ntask" + ble/edit/info/show text "$text" +} +function ble/complete/dabbrev/show-status { + local fib_ntask=${#_ble_util_fiberchain[@]} + ble/complete/dabbrev/.show-status.fib +} +function ble/complete/dabbrev/erase-status { + ble/edit/info/default +} +function ble/complete/dabbrev/initialize-variables { + local wordbreaks; ble/complete/get-wordbreaks + _ble_complete_dabbrev_wordbreaks=$wordbreaks + local left=${_ble_edit_str::_ble_edit_ind} + local original=${left##*[$wordbreaks]} + local p1=$((_ble_edit_ind-${#original})) p2=$_ble_edit_ind + _ble_edit_mark=$p1 + _ble_edit_ind=$p2 + _ble_complete_dabbrev_original=$original + local ret; ble/string#escape-for-extended-regex "$original" + local needle='(^|['$wordbreaks'])'$ret + _ble_complete_dabbrev_regex1=$needle + _ble_complete_dabbrev_regex2='('$needle'[^'$wordbreaks']*).*' + local index; ble/history/get-index + _ble_complete_dabbrev_index=$index + _ble_complete_dabbrev_pos=${#_ble_edit_str} + _ble_complete_dabbrev_stack=() +} +function ble/complete/dabbrev/reset { + local original=$_ble_complete_dabbrev_original + ble-edit/content/replace "$_ble_edit_mark" "$_ble_edit_ind" "$original" + ((_ble_edit_ind=_ble_edit_mark+${#original})) + _ble_edit_mark_active= +} +function ble/complete/dabbrev/search-in-history-entry { + local line=$1 index=$2 + local index_editing; ble/history/get-index -v index_editing + if ((index!=index_editing)); then + local pos=$dabbrev_pos + while [[ ${line:pos} && ${line:pos} =~ $_ble_complete_dabbrev_regex2 ]]; do + local rematch1=${BASH_REMATCH[1]} rematch2=${BASH_REMATCH[2]} + local match=${rematch1:${#rematch2}} + if [[ $match && $match != "$dabbrev_current_match" ]]; then + dabbrev_match=$match + dabbrev_match_pos=$((${#line}-${#BASH_REMATCH}+${#match})) + return 0 + else + ((pos++)) + fi + done + fi + return 1 +} +function ble/complete/dabbrev/.search.fib { + if [[ ! $fib_suspend ]]; then + local start=$_ble_complete_dabbrev_index + local index=$_ble_complete_dabbrev_index + local pos=$_ble_complete_dabbrev_pos + ((--start>=0)) || ble/history/get-count -v start + else + local start index pos; builtin eval -- "$fib_suspend" + fib_suspend= + fi + local dabbrev_match= + local dabbrev_pos=$pos + local dabbrev_current_match=${_ble_edit_str:_ble_edit_mark:_ble_edit_ind-_ble_edit_mark} + local line; ble/history/get-edited-entry -v line "$index" + if ! ble/complete/dabbrev/search-in-history-entry "$line" "$index"; then + ((index--,dabbrev_pos=0)) + local isearch_time=0 + local isearch_opts=stop_check:cyclic + isearch_opts=$isearch_opts:condition + local dabbrev_original=$_ble_complete_dabbrev_original + local dabbrev_regex1=$_ble_complete_dabbrev_regex1 + local needle='[[ $LINE =~ $dabbrev_regex1 ]] && ble/complete/dabbrev/search-in-history-entry "$LINE" "$INDEX"' + [[ $dabbrev_original ]] && needle='[[ $LINE == *"$dabbrev_original"* ]] && '$needle + isearch_opts=$isearch_opts:progress + local isearch_progress_callback=ble/complete/dabbrev/.show-status.fib + ble/history/isearch-backward-blockwise "$isearch_opts"; local ext=$? + ((ext==148)) && fib_suspend="start=$start index=$index pos=$pos" + if ((ext)); then + if ((${#_ble_complete_dabbrev_stack[@]})); then + ble/widget/.bell # 周回したので鳴らす + return 0 + else + return "$ext" + fi + fi + fi + local rec=$_ble_complete_dabbrev_index,$_ble_complete_dabbrev_pos,$_ble_edit_ind,$_ble_edit_mark + ble/array#push _ble_complete_dabbrev_stack "$rec:$_ble_edit_str" + local insert; ble-edit/content/replace-limited "$_ble_edit_mark" "$_ble_edit_ind" "$dabbrev_match" + ((_ble_edit_ind=_ble_edit_mark+${#insert})) + ((index>_ble_complete_dabbrev_index)) && + ble/widget/.bell # 周回 + _ble_complete_dabbrev_index=$index + _ble_complete_dabbrev_pos=$dabbrev_match_pos + ble/textarea#redraw +} +function ble/complete/dabbrev/next.fib { + ble/complete/dabbrev/.search.fib; local ext=$? + if ((ext==0)); then + _ble_edit_mark_active=insert + ble/complete/dabbrev/.show-status.fib + elif ((ext==148)); then + ble/complete/dabbrev/.show-status.fib + else + ble/widget/.bell + ble/widget/dabbrev/exit + ble/complete/dabbrev/reset + fib_kill=1 + fi + return "$ext" +} +function ble/widget/dabbrev-expand { + ble/complete/dabbrev/initialize-variables + ble/decode/keymap/push dabbrev + ble/util/fiberchain#initialize ble/complete/dabbrev + ble/util/fiberchain#push next + ble/util/fiberchain#resume +} +function ble/widget/dabbrev/next { + ble/util/fiberchain#push next + ble/util/fiberchain#resume +} +function ble/widget/dabbrev/prev { + if ((${#_ble_util_fiberchain[@]})); then + local ret; ble/array#pop _ble_util_fiberchain + if ((${#_ble_util_fiberchain[@]})); then + ble/util/fiberchain#resume + else + ble/complete/dabbrev/show-status + fi + elif ((${#_ble_complete_dabbrev_stack[@]})); then + local ret; ble/array#pop _ble_complete_dabbrev_stack + local rec str=${ret#*:} + ble/string#split rec , "${ret%%:*}" + ble-edit/content/reset-and-check-dirty "$str" + _ble_edit_ind=${rec[2]} + _ble_edit_mark=${rec[3]} + _ble_complete_dabbrev_index=${rec[0]} + _ble_complete_dabbrev_pos=${rec[1]} + ble/complete/dabbrev/show-status + else + ble/widget/.bell + return 1 + fi +} +function ble/widget/dabbrev/cancel { + if ((${#_ble_util_fiberchain[@]})); then + ble/util/fiberchain#clear + ble/complete/dabbrev/show-status + else + ble/widget/dabbrev/exit + ble/complete/dabbrev/reset + fi +} +function ble/widget/dabbrev/exit { + ble/decode/keymap/pop + _ble_edit_mark_active= + ble/complete/dabbrev/erase-status +} +function ble/widget/dabbrev/exit-default { + ble/widget/dabbrev/exit + ble/decode/widget/skip-lastwidget + ble/decode/widget/redispatch-by-keys "${KEYS[@]}" +} +function ble/widget/dabbrev/accept-line { + ble/widget/dabbrev/exit + ble-decode-key 13 +} +function ble-decode/keymap:dabbrev/define { + ble-bind -f __default__ 'dabbrev/exit-default' + ble-bind -f __line_limit__ nop + ble-bind -f 'C-g' 'dabbrev/cancel' + ble-bind -f 'C-x C-g' 'dabbrev/cancel' + ble-bind -f 'C-M-g' 'dabbrev/cancel' + ble-bind -f C-r 'dabbrev/next' + ble-bind -f C-s 'dabbrev/prev' + ble-bind -f RET 'dabbrev/exit' + ble-bind -f C-m 'dabbrev/exit' + ble-bind -f C-RET 'dabbrev/accept-line' + ble-bind -f C-j 'dabbrev/accept-line' +} +function ble/complete/action:cdpath/initialize { + DATA=$cdpath_basedir + ble/complete/action:file/initialize +} +function ble/complete/action:cdpath/complete { + CAND=$DATA$CAND ble/complete/action:file/complete +} +function ble/complete/action:cdpath/init-menu-item { + ble/color/face2g cmdinfo_cd_cdpath; g=$ret + if [[ :$comp_type: == *:vstat:* ]]; then + if [[ -h $CAND ]]; then + suffix='@' + elif [[ -d $CAND ]]; then + suffix='/' + fi + fi +} +function ble/complete/action:cdpath/get-desc { + local sgr0=$_ble_term_sgr0 sgr1= sgr2= + local g ret g1 g2 + ble/syntax/highlight/getg-from-filename "$DATA$CAND"; g1=$g + [[ $g1 ]] || { ble/color/face2g filename_warning; g1=$ret; } + ((g2=g1^_ble_color_gflags_Revert)) + ble/color/g2sgr "$g1"; sgr1=$ret + ble/color/g2sgr "$g2"; sgr2=$ret + ble/string#escape-for-display "$DATA$CAND" sgr1="$sgr2":sgr0="$sgr1" + local filename=$sgr1$ret$sgr0 + CAND=$DATA$CAND ble/complete/action:file/get-desc + desc="CDPATH $filename ($desc)" +} +function ble/cmdinfo/complete:cd/.impl { + local type=$1 + [[ $comps_flags == *v* ]] || return 1 + if [[ $COMPV == -* ]]; then + local action=word + case $type in + (pushd) + if [[ $COMPV == - || $COMPV == -n ]]; then + local "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe + ble/complete/cand/yield.initialize "$action" + ble/complete/cand/yield "$action" -n + fi ;; + (*) + COMP_PREFIX=$COMPV + local -a list=() + local "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe + ble/complete/cand/yield.initialize "$action" + [[ $COMPV == -* ]] && ble/complete/cand/yield "$action" "${COMPV}" + [[ $COMPV != *L* ]] && ble/complete/cand/yield "$action" "${COMPV}L" + [[ $COMPV != *P* ]] && ble/complete/cand/yield "$action" "${COMPV}P" + ((_ble_bash>=40200)) && [[ $COMPV != *e* ]] && ble/complete/cand/yield "$action" "${COMPV}e" + ((_ble_bash>=40300)) && [[ $COMPV != *@* ]] && ble/complete/cand/yield "$action" "${COMPV}@" ;; + esac + return 0 + fi + [[ :$comp_type: != *:[maA]:* && $COMPV =~ ^.+/ ]] && COMP_PREFIX=${BASH_REMATCH[0]} + [[ :$comp_type: == *:[maA]:* && ! $COMPV ]] && return 1 + if [[ ! $CDPATH ]]; then + ble/complete/source:dir + return "$?" + fi + ble/complete/source:tilde; local ext=$? + ((ext==148||ext==0)) && return "$ext" + local is_pwd_visited= is_cdpath_generated= + "${_ble_util_set_declare[@]//NAME/visited}" # WA #D1570 checked + local name names; ble/string#split names : "$CDPATH" + for name in "${names[@]}"; do + [[ $name ]] || continue + name=${name%/}/ + local action=cdpath + [[ ${name%/} == . || ${name%/} == "${PWD%/}" ]] && + is_pwd_visited=1 action=file + local -a candidates=() + local ret cand + ble/complete/source:file/.construct-pathname-pattern "$COMPV" + ble/complete/util/eval-pathname-expansion "$name$ret"; (($?==148)) && return 148 + ble/complete/source/test-limit ${#ret[@]} || return 1 + for cand in "${ret[@]}"; do + ((cand_iloop++%bleopt_complete_polling_cycle==0)) && + ble/complete/check-cancel && return 148 + [[ $cand && -d $cand ]] || continue + [[ $cand == / ]] || cand=${cand%/} + cand=${cand#"$name"} + ble/set#contains visited "$cand" && continue + ble/set#add visited "$cand" + ble/array#push candidates "$cand" + done + ((${#candidates[@]})) || continue + local flag_source_filter=1 + local cdpath_basedir=$name + ble/complete/cand/yield-filenames "$action" "${candidates[@]}" + [[ $action == cdpath ]] && is_cdpath_generated=1 + done + [[ $is_cdpath_generated ]] && + bleopt complete_menu_style=desc + if [[ ! $is_pwd_visited ]]; then + local -a candidates=() + local ret cand + ble/complete/source:file/.construct-pathname-pattern "$COMPV" + ble/complete/util/eval-pathname-expansion "${ret%/}/"; (($?==148)) && return 148 + ble/complete/source/test-limit ${#ret[@]} || return 1 + for cand in "${ret[@]}"; do + ((cand_iloop++%bleopt_complete_polling_cycle==0)) && + ble/complete/check-cancel && return 148 + [[ -d $cand ]] || continue + [[ $cand == / ]] || cand=${cand%/} + ble/set#contains visited "$cand" && continue + ble/array#push candidates "$cand" + done + local flag_source_filter=1 + ble/complete/cand/yield-filenames file "${candidates[@]}" + fi +} +function ble/cmdinfo/complete:cd { + ble/cmdinfo/complete:cd/.impl cd +} +function ble/cmdinfo/complete:pushd { + ble/cmdinfo/complete:cd/.impl pushd +} +blehook/invoke complete_load +blehook complete_load= +return 0 diff --git a/.local/src/blesh/lib/core-decode.emacs-rlfunc.txt b/.local/src/blesh/lib/core-decode.emacs-rlfunc.txt new file mode 100644 index 0000000..e0dbffd --- /dev/null +++ b/.local/src/blesh/lib/core-decode.emacs-rlfunc.txt @@ -0,0 +1,170 @@ +abort bell +accept-line accept-line +alias-expand-line alias-expand-line +arrow-key-prefix - +backward-byte @nomarked backward-byte +backward-char @nomarked backward-char +backward-delete-char delete-region-or delete-backward-char +backward-kill-line kill-backward-line +backward-kill-word kill-backward-cword +backward-word @nomarked backward-cword +beginning-of-history history-beginning +beginning-of-line @nomarked beginning-of-line +bracketed-paste-begin bracketed-paste +call-last-kbd-macro call-keyboard-macro +capitalize-word capitalize-eword +character-search character-search-forward +character-search-backward character-search-backward +clear-display clear-display +clear-screen clear-screen +complete complete +complete-command complete context=command +complete-filename complete context=filename +complete-hostname complete context=hostname +complete-into-braces complete insert_braces +complete-username complete context=username +complete-variable complete context=variable +copy-backward-word copy-backward-cword +copy-forward-word copy-forward-cword +copy-region-as-kill copy-region +dabbrev-expand dabbrev-expand +delete-char delete-forward-char +delete-char-or-list delete-forward-char-or-list +delete-horizontal-space delete-horizontal-space +digit-argument append-arg +display-shell-version display-shell-version +do-lowercase-version do-lowercase-version +downcase-word downcase-eword +dump-functions readline-dump-functions +dump-macros readline-dump-macros +dump-variables readline-dump-variables +dynamic-complete-history complete context=dynamic-history +edit-and-execute-command edit-and-execute-command +emacs-editing-mode nop +end-kbd-macro end-keyboard-macro +end-of-history history-end +end-of-line end-of-line +exchange-point-and-mark exchange-point-and-mark +forward-backward-delete-char delete-forward-backward-char +forward-byte @nomarked forward-byte +forward-char @nomarked forward-char +forward-search-history history-isearch-forward +forward-word @nomarked forward-cword +glob-complete-word complete context=glob +glob-expand-word complete context=glob:insert-all +glob-list-expansions complete context=glob:show_menu +history-and-alias-expand-line history-and-alias-expand-line +history-expand-line history-expand-line +history-search-backward history-search-backward empty=emulate-readline +history-search-forward history-search-forward empty=emulate-readline +history-substring-search-backward history-substring-search-backward +history-substring-search-forward history-substring-search-forward +insert-comment insert-comment +insert-completions complete insert_all +insert-last-argument insert-last-argument +kill-line kill-forward-line +kill-region kill-region-or kill-uword +kill-whole-line kill-line +kill-word kill-forward-cword +magic-space magic-space +menu-complete menu-complete +menu-complete-backward menu-complete backward +next-history history-next +next-screen-line @nomarked forward-graphical-line +non-incremental-forward-search-history history-nsearch-forward +non-incremental-forward-search-history-again history-nsearch-forward-again +non-incremental-reverse-search-history history-nsearch-backward +non-incremental-reverse-search-history-again history-nsearch-backward-again +old-menu-complete menu-complete +operate-and-get-next accept-and-next +overwrite-mode overwrite-mode +possible-command-completions complete show_menu:context=command +possible-completions complete show_menu +possible-filename-completions complete show_menu:context=filename +possible-hostname-completions complete show_menu:context=hostname +possible-username-completions complete show_menu:context=username +possible-variable-completions complete show_menu:context=variable +previous-history history-prev +previous-screen-line @nomarked backward-graphical-line +print-last-kbd-macro print-keyboard-macro +quoted-insert quoted-insert +re-read-init-file re-read-init-file +redraw-current-line redraw-line +reverse-search-history history-isearch-backward +revert-line emacs/revert +self-insert self-insert +set-mark set-mark +shell-backward-kill-word kill-backward-sword +shell-backward-word @nomarked backward-sword +shell-expand-line shell-expand-line +shell-forward-word @nomarked forward-sword +shell-kill-word kill-forward-sword +shell-transpose-words transpose-swords +skip-csi-sequence <IGNORE> +start-kbd-macro start-keyboard-macro +tab-insert tab-insert +tilde-expand tilde-expand +transpose-chars transpose-chars +transpose-words transpose-ewords +tty-status - +undo emacs/undo +universal-argument universal-arg +unix-filename-rubout kill-backward-fword +unix-line-discard kill-backward-line +unix-word-rubout kill-backward-uword +upcase-word upcase-eword +vi-append-eol - +vi-append-mode - +vi-arg-digit - +vi-prev-word vi-rlfunc/prev-word +vi-backward-word vi-command/backward-vword +vi-backward-bigword vi-command/backward-uword +vi-bword vi-command/backward-vword +vi-bWord vi-command/backward-uword +vi-end-word vi-rlfunc/end-word +vi-end-bigword vi-command/forward-uword-end +vi-eword vi-command/forward-vword-end +vi-eWord vi-command/forward-uword-end +vi-next-word vi-rlfunc/next-word +vi-forward-word vi-command/forward-vword +vi-forward-bigword vi-command/forward-uword +vi-fword vi-command/forward-vword +vi-fWord vi-command/forward-uword +vi-back-to-indent - +vi-change-case - +vi-change-char - +vi-change-to - +vi-char-search - +vi-column - +vi-complete - +vi-delete - +vi-delete-to - +vi-editing-mode vi-editing-mode +vi-eof-maybe - +vi-fetch-history - +vi-first-print - +vi-goto-mark - +vi-insert-beg - +vi-insertion-mode - +vi-match - +vi-movement-mode - +vi-overstrike - +vi-overstrike-delete - +vi-put - +vi-redo - +vi-replace - +vi-rubout - +vi-search - +vi-search-again - +vi-set-mark - +vi-subst - +vi-tilde-expand - +vi-unix-word-rubout - +vi-yank-arg - +vi-yank-pop - +vi-yank-to - +yank yank +yank-last-arg insert-last-argument +yank-nth-arg insert-nth-argument +yank-pop yank-pop +paste-from-clipboard paste-from-clipboard diff --git a/.local/src/blesh/lib/core-decode.vi_imap-rlfunc.txt b/.local/src/blesh/lib/core-decode.vi_imap-rlfunc.txt new file mode 100644 index 0000000..8b4dfac --- /dev/null +++ b/.local/src/blesh/lib/core-decode.vi_imap-rlfunc.txt @@ -0,0 +1,169 @@ +abort bell +accept-line accept-single-line-or-newline +alias-expand-line alias-expand-line +arrow-key-prefix - +backward-byte @nomarked backward-byte +backward-char @nomarked backward-char +backward-delete-char vi_imap/delete-region-or vi_imap/delete-backward-indent-or delete-backward-char +backward-kill-line kill-backward-line +backward-kill-word kill-backward-uword +backward-word @nomarked backward-sword +beginning-of-history history-beginning +beginning-of-line @nomarked beginning-of-line +bracketed-paste-begin vi_imap/bracketed-paste +call-last-kbd-macro call-keyboard-macro +capitalize-word capitalize-eword +character-search character-search-forward +character-search-backward character-search-backward +clear-display clear-display +clear-screen clear-screen +complete complete +complete-command complete context=command +complete-filename complete context=filename +complete-hostname complete context=hostname +complete-into-braces complete insert_braces +complete-username complete context=username +complete-variable complete context=variable +copy-backward-word copy-backward-sword +copy-forward-word copy-forward-sword +copy-region-as-kill copy-region-or copy-uword +dabbrev-expand dabbrev-expand +delete-char vi_imap/delete-region-or delete-forward-char +delete-char-or-list delete-forward-char-or-list +delete-horizontal-space delete-horizontal-space +digit-argument append-arg +display-shell-version display-shell-version +do-lowercase-version do-lowercase-version +downcase-word downcase-eword +dump-functions readline-dump-functions +dump-macros readline-dump-macros +dump-variables readline-dump-variables +dynamic-complete-history complete context=dynamic-history +edit-and-execute-command edit-and-execute-command +emacs-editing-mode emacs-editing-mode +end-kbd-macro end-keyboard-macro +end-of-history history-end +end-of-line @nomarked end-of-line +exchange-point-and-mark exchange-point-and-mark +forward-backward-delete-char delete-forward-backward-char +forward-byte @nomarked forward-byte +forward-char @nomarked forward-char +forward-search-history history-isearch-forward +forward-word @nomarked forward-uword +glob-complete-word complete context=glob +glob-expand-word complete context=glob:insert-all +glob-list-expansions complete context=glob:show_menu +history-and-alias-expand-line history-and-alias-expand-line +history-expand-line history-expand-line +history-search-backward history-search-backward empty=emulate-readline +history-search-forward history-search-forward empty=emulate-readline +history-substring-search-backward history-substring-search-backward +history-substring-search-forward history-substring-search-forward +insert-comment insert-comment +insert-completions complete insert_all +insert-last-argument insert-last-argument +kill-line kill-forward-line +kill-region kill-region-or kill-uword +kill-whole-line kill-line +kill-word kill-forward-uword +magic-space magic-space +menu-complete menu-complete +menu-complete-backward menu-complete backward +next-history history-next +next-screen-line @nomarked forward-graphical-line +non-incremental-forward-search-history history-nsearch-forward +non-incremental-forward-search-history-again history-nsearch-forward-again +non-incremental-reverse-search-history history-nsearch-backward +non-incremental-reverse-search-history-again history-nsearch-backward-again +old-menu-complete menu-complete +operate-and-get-next accept-and-next +overwrite-mode vi_imap/overwrite-mode +possible-command-completions complete show_menu:context=command +possible-completions complete show_menu +possible-filename-completions complete show_menu:context=filename +possible-hostname-completions complete show_menu:context=hostname +possible-username-completions complete show_menu:context=username +possible-variable-completions complete show_menu:context=variable +previous-history history-prev +previous-screen-line @nomarked backward-graphical-line +print-last-kbd-macro print-keyboard-macro +quoted-insert vi_imap/quoted-insert +re-read-init-file re-read-init-file +redraw-current-line redraw-line +reverse-search-history history-isearch-backward +revert-line - +self-insert self-insert +set-mark set-mark +shell-backward-kill-word kill-backward-sword +shell-backward-word @nomarked backward-sword +shell-expand-line shell-expand-line +shell-forward-word @nomarked forward-sword +shell-kill-word kill-forward-sword +shell-transpose-words transpose-swords +skip-csi-sequence <IGNORE> +start-kbd-macro start-keyboard-macro +tab-insert tab-insert +tilde-expand tilde-expand +transpose-chars transpose-chars +transpose-words transpose-ewords +tty-status - +undo - +universal-argument universal-arg +unix-filename-rubout kill-backward-fword +unix-line-discard kill-backward-line +unix-word-rubout kill-backward-uword +upcase-word upcase-eword +vi-append-eol - +vi-append-mode - +vi-arg-digit - +vi-back-to-indent - +vi-prev-word vi-rlfunc/prev-word +vi-backward-word vi-command/backward-vword +vi-backward-bigword vi-command/backward-uword +vi-bword vi-command/backward-vword +vi-bWord vi-command/backward-uword +vi-end-word vi-rlfunc/end-word +vi-end-bigword vi-command/forward-uword-end +vi-eword vi-command/forward-vword-end +vi-eWord vi-command/forward-uword-end +vi-next-word vi-rlfunc/next-word +vi-forward-word vi-command/forward-vword +vi-forward-bigword vi-command/forward-uword +vi-fword vi-command/forward-vword +vi-fWord vi-command/forward-uword +vi-change-case - +vi-change-char - +vi-change-to - +vi-char-search - +vi-column - +vi-complete - +vi-delete - +vi-delete-to - +vi-editing-mode nop +vi-eof-maybe - +vi-fetch-history - +vi-first-print - +vi-goto-mark - +vi-insert-beg - +vi-insertion-mode nop +vi-match - +vi-movement-mode vi_imap/normal-mode +vi-overstrike - +vi-overstrike-delete - +vi-put - +vi-redo - +vi-replace vi_imap/overwrite-mode +vi-rubout - +vi-search - +vi-search-again - +vi-set-mark - +vi-subst - +vi-tilde-expand - +vi-unix-word-rubout vi_imap/delete-backward-word +vi-yank-arg - +vi-yank-pop - +vi-yank-to - +yank yank +yank-last-arg insert-last-argument +yank-nth-arg insert-nth-argument +yank-pop yank-pop diff --git a/.local/src/blesh/lib/core-decode.vi_nmap-rlfunc.txt b/.local/src/blesh/lib/core-decode.vi_nmap-rlfunc.txt new file mode 100644 index 0000000..a3db96d --- /dev/null +++ b/.local/src/blesh/lib/core-decode.vi_nmap-rlfunc.txt @@ -0,0 +1,170 @@ +abort bell +accept-line accept-single-line-or vi-command/forward-first-non-space +alias-expand-line vi_nmap/@edit alias-expand-line +arrow-key-prefix - +backward-byte vi-command/backward-byte +backward-char vi-command/backward-char +backward-delete-char - +backward-kill-line - +backward-kill-word - +backward-word vi-command/backward-vword +beginning-of-history - +beginning-of-line vi-command/beginning-of-line +bracketed-paste-begin vi-command/bracketed-paste +call-last-kbd-macro call-keyboard-macro +capitalize-word vi_nmap/capitalize-eword +character-search vi_nmap/@motion character-search-forward +character-search-backward vi_nmap/@motion character-search-backward +clear-display clear-display +clear-screen clear-screen +complete - +complete-command - +complete-filename - +complete-hostname - +complete-into-braces - +complete-username - +complete-variable - +copy-backward-word - +copy-forward-word - +copy-region-as-kill - +dabbrev-expand - +delete-char vi_nmap/kill-forward-char +delete-char-or-list - +delete-horizontal-space - +digit-argument vi-command/append-arg +display-shell-version vi_nmap/@adjust display-shell-version +do-lowercase-version do-lowercase-version +downcase-word vi_nmap/downcase-eword +dump-functions vi_nmap/@adjust readline-dump-functions +dump-macros vi_nmap/@adjust readline-dump-macros +dump-variables vi_nmap/@adjust readline-dump-variables +dynamic-complete-history - +edit-and-execute-command vi-command/edit-and-execute-line +emacs-editing-mode emacs-editing-mode +end-kbd-macro end-keyboard-macro +end-of-history - +end-of-line vi-command/forward-eol +exchange-point-and-mark - +forward-backward-delete-char - +forward-byte vi-command/forward-byte +forward-char vi-command/forward-char +forward-search-history history-isearch-forward +forward-word vi-command/forward-vword +glob-complete-word - +glob-expand-word - +glob-list-expansions - +history-and-alias-expand-line vi_nmap/@edit history-and-alias-expand-line +history-expand-line vi_nmap/@edit history-expand-line +history-search-backward history-search-backward empty=emulate-readline +history-search-forward history-search-forward empty=emulate-readline +history-substring-search-backward history-substring-search-backward +history-substring-search-forward history-substring-search-forward +insert-comment vi-rlfunc/insert-comment +insert-completions - +insert-last-argument - +kill-line vi_nmap/kill-forward-line +kill-region - +kill-whole-line - +kill-word vi-rlfunc/kill-word +magic-space - +menu-complete - +menu-complete-backward - +next-history history-next +next-screen-line - +non-incremental-forward-search-history history-nsearch-forward +non-incremental-forward-search-history-again history-nsearch-forward-again +non-incremental-reverse-search-history history-nsearch-backward +non-incremental-reverse-search-history-again history-nsearch-backward-again +old-menu-complete - +operate-and-get-next - +overwrite-mode vi_nmap/replace-mode +possible-command-completions complete show_menu:context=command +possible-completions complete show_menu +possible-filename-completions complete show_menu:context=filename +possible-hostname-completions complete show_menu:context=hostname +possible-username-completions complete show_menu:context=username +possible-variable-completions complete show_menu:context=variable +previous-history history-prev +previous-screen-line - +print-last-kbd-macro print-keyboard-macro +quoted-insert vi-rlfunc/quoted-insert +re-read-init-file vi_nmap/@adjust re-read-init-file +redraw-current-line redraw-line +reverse-search-history history-isearch-backward +revert-line vi_nmap/revert +self-insert - +set-mark vi_nmap/charwise-visual-mode +shell-backward-kill-word - +shell-backward-word - +shell-expand-line - +shell-forward-word - +shell-kill-word - +shell-transpose-words - +skip-csi-sequence <IGNORE> +start-kbd-macro start-keyboard-macro +tab-insert - +tilde-expand vi_nmap/@edit tilde-expand +transpose-chars transpose-chars +transpose-words - +tty-status - +undo vi_nmap/undo +universal-argument - +unix-filename-rubout - +unix-line-discard vi-rlfunc/unix-line-discard +unix-word-rubout - +upcase-word vi_nmap/upcase-eword +vi-append-eol vi_nmap/append-mode-at-end-of-line +vi-append-mode vi_nmap/append-mode +vi-arg-digit vi-command/append-arg +vi-prev-word vi-rlfunc/prev-word +vi-backward-word vi-command/backward-vword +vi-backward-bigword vi-command/backward-uword +vi-bword vi-command/backward-vword +vi-bWord vi-command/backward-uword +vi-end-word vi-rlfunc/end-word +vi-end-bigword vi-command/forward-uword-end +vi-eword vi-command/forward-vword-end +vi-eWord vi-command/forward-uword-end +vi-next-word vi-rlfunc/next-word +vi-forward-word vi-command/forward-vword +vi-forward-bigword vi-command/forward-uword +vi-fword vi-command/forward-vword +vi-fWord vi-command/forward-uword +vi-back-to-indent - +vi-change-case vi-command/operator toggle_case +vi-change-char vi_nmap/replace-char +vi-change-to vi-rlfunc/change-to +vi-char-search vi-rlfunc/char-search +vi-column vi-command/nth-column +vi-complete - +vi-delete vi_nmap/kill-forward-char +vi-delete-to vi-rlfunc/delete-to +vi-editing-mode vi_nmap/insert-mode +vi-eof-maybe vi-rlfunc/eof-maybe +vi-fetch-history vi-command/history-end +vi-first-print vi-command/first-non-space +vi-goto-mark vi-command/goto-mark +vi-insert-beg vi_nmap/insert-mode-at-first-non-space +vi-insertion-mode vi_nmap/insert-mode +vi-match vi-command/search-matchpair-or vi-command/percentage-line +vi-movement-mode nop +vi-overstrike - +vi-overstrike-delete - +vi-put vi-rlfunc/put +vi-redo vi_nmap/repeat +vi-replace vi_nmap/replace-mode +vi-rubout vi_nmap/kill-backward-char +vi-search vi-rlfunc/search +vi-search-again vi-rlfunc/search-again +vi-set-mark vi-command/set-mark +vi-subst vi-rlfunc/subst +vi-tilde-expand - +vi-undo vi_nmap/undo +vi-unix-word-rubout - +vi-yank-arg vi-rlfunc/yank-arg +vi-yank-pop - +vi-yank-to vi-rlfunc/yank-to +yank yank +yank-last-arg - +yank-nth-arg - +yank-pop - diff --git a/.local/src/blesh/lib/core-edit.ignoreeof-messages.txt b/.local/src/blesh/lib/core-edit.ignoreeof-messages.txt new file mode 100644 index 0000000..6588f87 --- /dev/null +++ b/.local/src/blesh/lib/core-edit.ignoreeof-messages.txt @@ -0,0 +1,32 @@ +Gebruik Kaart na Los Tronk +Използвайте „exit“, за да излезете от обвивката. +Utilitzeu ?exit? per a eixir de l'int?rpret d'ordres. +Shell lze ukončit příkazem „exit“. +Brug "exit" for at forlade skallen. +Benutze "exit" um die Shell zu verlassen. +Χρήση «exit» για έξοδο από το κέλυφος. +Use “[1mexit[0m” to leave the shell. +Use “exit” to leave the shell. +Uzu «exit» por eliri el la ŝelo. +Use "exit" para dejar el shell. +Kirjoita ”exit” poistuaksesi komentotulkista. +Utilisez « exit » pour quitter le shell. +Úsáid "exit" le scoir den mblaosc. +Use «exit» para deixar o shell. +Koristite „exit” za napuštanje ljuske. +„exit” használatával lehet elhagyni a parancsértelmezőt. +Gunakan "exit" untuk meninggalkan shell. +Usare "exit" per uscire dalla shell. +シェルから脱出するには "exit" を使用してください。 +Naudokite „exit“, jei norite išeiti iš ap. +Gebruik "exit" om de shell te verlaten. +Użyj "exit", aby opuścić tę powłokę. +Use "exit" para sair da `shell'. +Na opustenie shellu použite „exit“. +Uporabite "exit", če želite zapustiti lupino. +Користите „exit“ да напустите шкољку. +Använd "exit" fär att lämna skalet. +Kabuğu bırakmak için "exit" kullanın. +Використовуйте "exit", щоб вийти з оболонки. +Dùng "exit" để rời hệ vỏ. +使用 "exit" 退出 shell 。 diff --git a/.local/src/blesh/lib/core-syntax.sh b/.local/src/blesh/lib/core-syntax.sh new file mode 100644 index 0000000..bd566f9 --- /dev/null +++ b/.local/src/blesh/lib/core-syntax.sh @@ -0,0 +1,5355 @@ +# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license +function ble/syntax/util/is-directory { + local path=$1 + if [[ ( $OSTYPE == cygwin || $OSTYPE == msys ) && $path == //* ]]; then + [[ $path == // ]] + else + [[ -d $path ]] + fi +} +function ble/syntax/urange#update { + local prefix=$1 + local p1=$2 p2=${3:-$2} + ((0<=p1&&p1<p2)) || return 1 + (((${prefix}umin<0||${prefix}umin>p1)&&(${prefix}umin=p1), + (${prefix}umax<0||${prefix}umax<p2)&&(${prefix}umax=p2))) +} +function ble/syntax/wrange#update { + local prefix=$1 + local p1=$2 p2=${3:-$2} + ((0<=p1&&p1<=p2)) || return 1 + (((${prefix}umin<0||${prefix}umin>p1)&&(${prefix}umin=p1), + (${prefix}umax<0||${prefix}umax<p2)&&(${prefix}umax=p2))) +} +function ble/syntax/urange#shift { + local prefix=$1 + ((${prefix}umin>=end0?(${prefix}umin+=shift):( + ${prefix}umin>=beg&&(${prefix}umin=end)), + ${prefix}umax>end0?(${prefix}umax+=shift):( + ${prefix}umax>beg&&(${prefix}umax=beg)), + ${prefix}umin>=${prefix}umax&& + (${prefix}umin=${prefix}umax=-1))) +} +function ble/syntax/wrange#shift { + local prefix=$1 + ((${prefix}umin>=end0?(${prefix}umin+=shift):( + ${prefix}umin>beg&&(${prefix}umin=end)), + ${prefix}umax>=end0?(${prefix}umax+=shift):( + ${prefix}umax>=beg&&(${prefix}umax=beg)), + ${prefix}umin==0&&++${prefix}umin, + ${prefix}umin>${prefix}umax&& + (${prefix}umin=${prefix}umax=-1))) +} +_ble_syntax_text= +_ble_syntax_lang=bash +_ble_syntax_stat=() +_ble_syntax_nest=() +_ble_syntax_tree=() +_ble_syntax_attr=() +_ble_syntax_TREE_WIDTH=5 +function ble/syntax/tree-enumerate/.add-root-element { + local wtype=$1 wlen=$2 tclen=$3 tplen=$4 + [[ ! ${wtype//[0-9]} && ${_ble_syntax_bash_command_EndWtype[wtype]} ]] && + wtype=${_ble_syntax_bash_command_EndWtype[wtype]} + TE_root="$wtype $wlen $tclen $tplen -- $TE_root" +} +function ble/syntax/tree-enumerate/.initialize { + if [[ ! ${_ble_syntax_stat[iN]} ]]; then + TE_root= TE_i=-1 TE_nofs=0 + return 0 + fi + local -a stat nest + ble/string#split-words stat "${_ble_syntax_stat[iN]}" + local wtype=${stat[2]} + local wlen=${stat[1]} + local nlen=${stat[3]} inest + ((inest=nlen<0?nlen:iN-nlen)) + local tclen=${stat[4]} + local tplen=${stat[5]} + TE_root= + ((iN>0)) && TE_root=${_ble_syntax_tree[iN-1]} + while + if ((wlen>=0)); then + ble/syntax/tree-enumerate/.add-root-element "$wtype" "$wlen" "$tclen" "$tplen" + tclen=0 + fi + ((inest>=0)) + do + ble/util/assert '[[ ${_ble_syntax_nest[inest]} ]]' "$FUNCNAME/FATAL1" || break + ble/string#split-words nest "${_ble_syntax_nest[inest]}" + local olen=$((iN-inest)) + tplen=${nest[4]} + ((tplen>=0&&(tplen+=olen))) + ble/syntax/tree-enumerate/.add-root-element "${nest[7]}" "$olen" "$tclen" "$tplen" + wtype=${nest[2]} wlen=${nest[1]} nlen=${nest[3]} tclen=0 tplen=${nest[5]} + ((wlen>=0&&(wlen+=olen), + tplen>=0&&(tplen+=olen), + nlen>=0&&(nlen+=olen), + inest=nlen<0?nlen:iN-nlen)) + ble/util/assert '((nlen<0||nlen>olen))' "$FUNCNAME/FATAL2" || break + done + if [[ $TE_root ]]; then + ((TE_i=iN)) + else + ((TE_i=tclen>=0?iN-tclen:tclen)) + fi + ((TE_nofs=0)) +} +function ble/syntax/tree-enumerate/.impl { + local islast=1 + while ((TE_i>0)); do + local -a node + if ((TE_i<iN)); then + ble/string#split-words node "${_ble_syntax_tree[TE_i-1]}" + else + ble/string#split-words node "${TE_root:-${_ble_syntax_tree[iN-1]}}" + fi + ble/util/assert '((TE_nofs<${#node[@]}))' "$FUNCNAME(i=$TE_i,iN=$iN,TE_nofs=$TE_nofs,node=${node[*]},command=$@)/FATAL1" || break + local wtype=${node[TE_nofs]} wlen=${node[TE_nofs+1]} tclen=${node[TE_nofs+2]} tplen=${node[TE_nofs+3]} attr=${node[TE_nofs+4]} + local wbegin=$((wlen<0?wlen:TE_i-wlen)) + local tchild=$((tclen<0?tclen:TE_i-tclen)) + local tprev=$((tplen<0?tplen:TE_i-tplen)) + "$@" + ble/util/assert '((tprev<TE_i))' "$FUNCNAME/FATAL2" || break + ((TE_i=tprev,TE_nofs=0,islast=0)) + done +} +function ble/syntax/tree-enumerate-children { + ((0<tchild&&tchild<=TE_i)) || return 1 + local TE_nofs=$((TE_i==tchild?TE_nofs+_ble_syntax_TREE_WIDTH:0)) + local TE_i=$tchild + ble/syntax/tree-enumerate/.impl "$@" +} +function ble/syntax/tree-enumerate-break () ((tprev=-1)) +function ble/syntax/tree-enumerate { + local TE_root TE_i TE_nofs + [[ ${iN:+set} ]] || local iN=${#_ble_syntax_text} + ble/syntax/tree-enumerate/.initialize + ble/syntax/tree-enumerate/.impl "$@" +} +function ble/syntax/tree-enumerate-in-range { + local beg=$1 end=$2 + local proc=$3 + local -a node + local TE_i TE_nofs + for ((TE_i=end;TE_i>=beg;TE_i--)); do + ((TE_i>0)) && [[ ${_ble_syntax_tree[TE_i-1]} ]] || continue + ble/string#split-words node "${_ble_syntax_tree[TE_i-1]}" + local flagUpdateNode= + for ((TE_nofs=0;TE_nofs<${#node[@]};TE_nofs+=_ble_syntax_TREE_WIDTH)); do + local wtype=${node[TE_nofs]} wlen=${node[TE_nofs+1]} wattr=${node[TE_nofs+4]} + local wbeg=$((wlen<0?wlen:TE_i-wlen)) wend=$TE_i + "${@:3}" + done + done +} +function ble/syntax/print-status/.graph { + local char=$1 + if ble/util/isprint+ "$char"; then + graph="'$char'" + return 0 + else + local ret + ble/util/s2c "$char" + local code=$ret + if ((code<32)); then + ble/util/c2s $((code+64)) + graph="$_ble_term_rev^$ret$_ble_term_sgr0" + elif ((code==127)); then + graph="$_ble_term_rev^?$_ble_term_sgr0" + elif ((128<=code&&code<160)); then + ble/util/c2s $((code-64)) + graph="${_ble_term_rev}M-^$ret$_ble_term_sgr0" + else + graph="'$char' ($code)" + fi + fi +} +function ble/syntax/print-status/.tree-prepend { + local j=$1 + local value=$2${tree[j]} + tree[j]=$value + ((max_tree_width<${#value}&&(max_tree_width=${#value}))) +} +function ble/syntax/print-status/.dump-arrays/.append-attr-char { + if (($?==0)); then + attr="${attr}$1" + else + attr="${attr} " + fi +} +function ble/syntax/print-status/ctx#get-text { + local sgr + ble/syntax/ctx#get-name "$1" + ret=${ret#BLE_} + if [[ ! $ret ]]; then + ble/color/face2sgr syntax_error + ret="${ret}CTX$1$_ble_term_sgr0" + fi +} +function ble/syntax/print-status/word.get-text { + local index=$1 + ble/string#split-words word "${_ble_syntax_tree[index]}" + local out= ret + if [[ $word ]]; then + local nofs=$((${#word[@]}/_ble_syntax_TREE_WIDTH*_ble_syntax_TREE_WIDTH)) + while (((nofs-=_ble_syntax_TREE_WIDTH)>=0)); do + local axis=$((index+1)) + local wtype=${word[nofs]} + if [[ $wtype =~ ^[0-9]+$ ]]; then + ble/syntax/print-status/ctx#get-text "$wtype"; wtype=$ret + elif [[ $wtype =~ ^n* ]]; then + wtype=$sgr_quoted\"${wtype:1}\"$_ble_term_sgr0 + else + wtype=$sgr_error${wtype}$_ble_term_sgr0 + fi + local b=$((axis-word[nofs+1])) e=$axis + local _prev=${word[nofs+3]} _child=${word[nofs+2]} + if ((_prev>=0)); then + _prev="@$((axis-_prev-1))>" + else + _prev= + fi + if ((_child>=0)); then + _child=">@$((axis-_child-1))" + else + _child= + fi + local wattr=${word[nofs+4]} _wattr= + if [[ $wattr != - ]]; then + wattr="/(wattr=$wattr)" + else + wattr= + fi + out=" word=$wtype:$_prev$b-$e$_child$wattr$out" + for ((;b<index;b++)); do + ble/syntax/print-status/.tree-prepend "$b" '|' + done + ble/syntax/print-status/.tree-prepend "$index" '+' + done + word=$out + fi +} +function ble/syntax/print-status/nest.get-text { + local index=$1 + ble/string#split-words nest "${_ble_syntax_nest[index]}" + if [[ $nest ]]; then + local ret + ble/syntax/print-status/ctx#get-text "${nest[0]}"; local nctx=$ret + local nword=- + if ((nest[1]>=0)); then + ble/syntax/print-status/ctx#get-text "${nest[2]}"; local swtype=$ret + local wbegin=$((index-nest[1])) + nword="$swtype:$wbegin-" + fi + local nnest=- + ((nest[3]>=0)) && nnest="'${nest[7]}':$((index-nest[3]))-" + local nchild=- + if ((nest[4]>=0)); then + local tchild=$((index-nest[4])) + nchild='$'$tchild + if ! ((0<tchild&&tchild<=index)) || [[ ! ${_ble_syntax_tree[tchild-1]} ]]; then + nchild=$sgr_error$nchild$_ble_term_sgr0 + fi + fi + local nprev=- + if ((nest[5]>=0)); then + local tprev=$((index-nest[5])) + nprev='$'$tprev + if ! ((0<tprev&&tprev<=index)) || [[ ! ${_ble_syntax_tree[tprev-1]} ]]; then + nprev=$sgr_error$nprev$_ble_term_sgr0 + fi + fi + local nparam=${nest[6]} + if [[ $nparam == none ]]; then + nparam= + else + nparam=${nparam//$_ble_term_FS/$'\e[7m^\\\e[m'} + nparam=" nparam=$nparam" + fi + nest=" nest=($nctx w=$nword n=$nnest t=$nchild:$nprev$nparam)" + fi +} +function ble/syntax/print-status/stat.get-text { + local index=$1 + ble/string#split-words stat "${_ble_syntax_stat[index]}" + if [[ $stat ]]; then + local ret + ble/syntax/print-status/ctx#get-text "${stat[0]}"; local stat_ctx=$ret + local stat_word=- + if ((stat[1]>=0)); then + ble/syntax/print-status/ctx#get-text "${stat[2]}"; local stat_wtype=$ret + stat_word="$stat_wtype:$((index-stat[1]))-" + fi + local stat_inest=- + if ((stat[3]>=0)); then + local inest=$((index-stat[3])) + stat_inest="@$inest" + if ((inest<0)) || [[ ! ${_ble_syntax_nest[inest]} ]]; then + stat_inest=$sgr_error$stat_inest$_ble_term_sgr0 + fi + fi + local stat_child=- + if ((stat[4]>=0)); then + local tchild=$((index-stat[4])) + stat_child='$'$tchild + if ! ((0<tchild&&tchild<=index)) || [[ ! ${_ble_syntax_tree[tchild-1]} ]]; then + stat_child=$sgr_error$stat_child$_ble_term_sgr0 + fi + fi + local stat_prev=- + if ((stat[5]>=0)); then + local tprev=$((index-stat[5])) + stat_prev='$'$tprev + if ! ((0<tprev&&tprev<=index)) || [[ ! ${_ble_syntax_tree[tprev-1]} ]]; then + stat_prev=$sgr_error$stat_prev$_ble_term_sgr0 + fi + fi + local snparam=${stat[6]} + if [[ $snparam == none ]]; then + snparam= + else + snparam=${snparam//"$_ble_term_FS"/$'\e[7m^\\\e[m'} + snparam=" nparam=$snparam" + fi + local stat_lookahead= + ((stat[7]!=1)) && stat_lookahead=" >>${stat[7]}" + stat=" stat=($stat_ctx w=$stat_word n=$stat_inest t=$stat_child:$stat_prev$snparam$stat_lookahead)" + fi +} +function ble/syntax/print-status/.dump-arrays { + local -a tree char line + tree=() + char=() + line=() + local ret + ble/color/face2sgr syntax_error; local sgr_error=$ret + ble/color/face2sgr syntax_quoted; local sgr_quoted=$ret + local i max_tree_width=0 + for ((i=0;i<=iN;i++)); do + local attr=" ${_ble_syntax_attr[i]:-|}" + if ((_ble_syntax_attr_umin<=i&&i<_ble_syntax_attr_umax)); then + attr="${attr:${#attr}-2:2}*" + else + attr="${attr:${#attr}-2:2} " + fi + [[ ${_ble_highlight_layer_syntax1_table[i]} ]] && ble/color/g2sgr "${_ble_highlight_layer_syntax1_table[i]}" + ble/syntax/print-status/.dump-arrays/.append-attr-char "${ret}a${_ble_term_sgr0}" + [[ ${_ble_highlight_layer_syntax2_table[i]} ]] && ble/color/g2sgr "${_ble_highlight_layer_syntax2_table[i]}" + ble/syntax/print-status/.dump-arrays/.append-attr-char "${ret}w${_ble_term_sgr0}" + [[ ${_ble_highlight_layer_syntax3_table[i]} ]] && ble/color/g2sgr "${_ble_highlight_layer_syntax3_table[i]}" + ble/syntax/print-status/.dump-arrays/.append-attr-char "${ret}e${_ble_term_sgr0}" + [[ ${_ble_syntax_stat_shift[i]} ]] + ble/syntax/print-status/.dump-arrays/.append-attr-char s + local index=000$i + index=${index:${#index}-3:3} + local word nest stat + ble/syntax/print-status/word.get-text "$i" + ble/syntax/print-status/nest.get-text "$i" + ble/syntax/print-status/stat.get-text "$i" + local graph= + ble/syntax/print-status/.graph "${_ble_syntax_text:i:1}" + char[i]="$attr $index $graph" + line[i]=$word$nest$stat + done + resultA='_ble_syntax_attr/tree/nest/stat?'$'\n' + ble/string#reserve-prototype "$max_tree_width" + for ((i=0;i<=iN;i++)); do + local t=${tree[i]}${_ble_string_prototype::max_tree_width} + resultA="$resultA${char[i]} ${t::max_tree_width}${line[i]}"$'\n' + done +} +function ble/syntax/print-status/.dump-tree/proc1 { + local tip="| "; tip=${tip:islast:1} + prefix="$prefix$tip " ble/syntax/tree-enumerate-children ble/syntax/print-status/.dump-tree/proc1 + resultB="$prefix\_ '${_ble_syntax_text:wbegin:wlen}'$nl$resultB" +} +function ble/syntax/print-status/.dump-tree { + resultB= + local nl=$_ble_term_nl + local prefix= + ble/syntax/tree-enumerate ble/syntax/print-status/.dump-tree/proc1 +} +function ble/syntax/print-status { + local iN=${#_ble_syntax_text} + local resultA + ble/syntax/print-status/.dump-arrays + local resultB + ble/syntax/print-status/.dump-tree + local result=$resultA$resultB + if [[ $1 == -v && $2 ]]; then + local "${2%%\[*\]}" && ble/util/upvar "$2" "$result" + else + ble/util/print "$result" + fi +} +function ble/syntax/print-layer-buffer.draw { + local layer_name=$1 + local -a keys vals + builtin eval "keys=(\"\${!_ble_highlight_layer_${layer_name}_buff[@]}\")" + builtin eval "vals=(\"\${_ble_highlight_layer_${layer_name}_buff[@]}\")" + local ret sgr0=$_ble_term_sgr0 + ble/color/face2sgr command_builtin; local sgr1=$ret + ble/color/face2sgr syntax_varname; local sgr2=$ret + ble/color/face2sgr syntax_quoted; local sgr3=$ret + ble/canvas/put.draw "${sgr1}buffer${sgr0} ${sgr2}$layer_name${sgr0}=(" + local i count=0 + for ((i=0;i<${#keys[@]};i++)); do + local key=${keys[i]} val=${vals[i]} + while ((count++<key)); do + ((count==1)) || ble/canvas/put.draw ' ' + ble/canvas/put.draw $'\e[91munset\e[m' + done + ((count==1)) || ble/canvas/put.draw ' ' + ble/string#quote-word "$val" quote-empty:sgrq="$sgr3" + ble/canvas/put.draw "$ret" + done + ble/canvas/put.draw ")$_ble_term_nl" +} +function ble/syntax/parse/generate-stat { + ((ilook<=i&&(ilook=i+1))) + _stat="$ctx $((wbegin<0?wbegin:i-wbegin)) $wtype $((inest<0?inest:i-inest)) $((tchild<0?tchild:i-tchild)) $((tprev<0?tprev:i-tprev)) ${nparam:-none} $((ilook-i))" +} +function ble/syntax/parse/set-lookahead { + ((i+$1>ilook&&(ilook=i+$1))) +} +function ble/syntax/parse/tree-append { + [[ $debug_p1 ]] && ble/util/assert '((i-1>=debug_p1))' "Wrong call of tree-append: Condition violation (p1=$debug_p1 i=$i iN=$iN)." + local type=$1 + local beg=$2 end=$i + local len=$((end-beg)) + ((len==0)) && return 0 + local tchild=$3 tprev=$4 + local ochild=-1 oprev=-1 + ((tchild>=0&&(ochild=i-tchild))) + ((tprev>=0&&(oprev=i-tprev))) + [[ $type =~ ^[0-9]+$ ]] && ble/syntax/parse/touch-updated-word "$i" + _ble_syntax_tree[i-1]="$type $len $ochild $oprev - ${_ble_syntax_tree[i-1]}" +} +function ble/syntax/parse/word-push { + wtype=$1 wbegin=$2 tprev=$tchild tchild=-1 +} +function ble/syntax/parse/word-pop { + ble/syntax/parse/tree-append "$wtype" "$wbegin" "$tchild" "$tprev" + ((wbegin=-1,wtype=-1,tchild=i)) + ble/syntax/parse/nest-reset-tprev +} +function ble/syntax/parse/word-cancel { + local -a word + ble/string#split-words word "${_ble_syntax_tree[i-1]}" + local wlen=${word[1]} tplen=${word[3]} + local wbegin=$((i-wlen)) + tchild=$((tplen<0?tplen:i-tplen)) + ble/array#fill-range _ble_syntax_tree "$wbegin" "$i" '' +} +function ble/syntax/parse/nest-push { + local wlen=$((wbegin<0?wbegin:i-wbegin)) + local nlen=$((inest<0?inest:i-inest)) + local tclen=$((tchild<0?tchild:i-tchild)) + local tplen=$((tprev<0?tprev:i-tprev)) + _ble_syntax_nest[i]="$ctx $wlen $wtype $nlen $tclen $tplen ${nparam:-none} ${2:-none}" + ((ctx=$1,inest=i,wbegin=-1,wtype=-1,tprev=tchild,tchild=-1)) + nparam= +} +function ble/syntax/parse/nest-pop { + ((inest<0)) && return 1 + local -a parentNest + ble/string#split-words parentNest "${_ble_syntax_nest[inest]}" + local ntype=${parentNest[7]} nbeg=$inest + ble/syntax/parse/tree-append "n$ntype" "$nbeg" "$tchild" "$tprev" + local wlen=${parentNest[1]} nlen=${parentNest[3]} tplen=${parentNest[5]} + ((ctx=parentNest[0])) + ((wtype=parentNest[2])) + ((wbegin=wlen<0?wlen:nbeg-wlen, + inest=nlen<0?nlen:nbeg-nlen, + tchild=i, + tprev=tplen<0?tplen:nbeg-tplen)) + nparam=${parentNest[6]} + [[ $nparam == none ]] && nparam= +} +function ble/syntax/parse/nest-type { + local _var=ntype + [[ $1 == -v ]] && _var=$2 + if ((inest<0)); then + builtin eval "$_var=" + return 1 + else + builtin eval "$_var=\"\${_ble_syntax_nest[inest]##* }\"" + fi +} +function ble/syntax/parse/nest-ctx { + nctx= + ((inest>=0)) || return 1 + nctx=${_ble_syntax_nest[inest]%% *} +} +function ble/syntax/parse/nest-reset-tprev { + if ((inest<0)); then + tprev=-1 + else + local -a nest + ble/string#split-words nest "${_ble_syntax_nest[inest]}" + local tclen=${nest[4]} + ((tprev=tclen<0?tclen:inest-tclen)) + fi +} +function ble/syntax/parse/nest-equals { + local parent_inest=$1 + while :; do + ((parent_inest<i1)) && return 0 # 変更していない範囲 または -1 + ((parent_inest<i2)) && return 1 # 変更によって消えた範囲 + local _onest=${_tail_syntax_nest[parent_inest-i2]} + local _nnest=${_ble_syntax_nest[parent_inest]} + [[ $_onest != "$_nnest" ]] && return 1 + local -a onest; ble/string#split-words onest "$_onest" + ble/util/assert \ + '((onest[3]!=0&&onest[3]<=parent_inest))' \ + "invalid nest onest[3]=${onest[3]} parent_inest=$parent_inest text=$text" || return 0 + ((parent_inest=onest[3]<0?onest[3]:(parent_inest-onest[3]))) + done +} +_ble_syntax_attr_umin=-1 _ble_syntax_attr_umax=-1 +_ble_syntax_word_umin=-1 _ble_syntax_word_umax=-1 +_ble_syntax_word_defer_umin=-1 _ble_syntax_word_defer_umax=-1 +function ble/syntax/parse/touch-updated-attr { + ble/syntax/urange#update _ble_syntax_attr_ "$1" $(($1+1)) +} +function ble/syntax/parse/touch-updated-word { + ble/util/assert "(($1>0))" "invalid word position $1" + ble/syntax/wrange#update _ble_syntax_word_ "$1" +} +_ble_ctx_UNSPECIFIED=0 +_ble_ctx_ARGX=3 +_ble_ctx_ARGX0=18 +_ble_ctx_ARGI=4 +_ble_ctx_ARGQ=61 +_ble_ctx_CMDX=1 +_ble_ctx_CMDX1=17 +_ble_ctx_CMDXT=49 +_ble_ctx_CMDXC=26 +_ble_ctx_CMDXE=43 +_ble_ctx_CMDXD0=38 +_ble_ctx_CMDXD=68 +_ble_ctx_CMDXV=13 +_ble_ctx_CMDI=2 +_ble_ctx_VRHS=11 +_ble_ctx_QUOT=5 +_ble_ctx_EXPR=8 +_ble_attr_ERR=6 +_ble_attr_VAR=7 +_ble_attr_QDEL=9 +_ble_attr_QESC=81 +_ble_attr_DEF=10 +_ble_attr_DEL=12 +_ble_attr_HISTX=21 +_ble_attr_FUNCDEF=22 +_ble_ctx_PARAM=14 +_ble_ctx_PWORD=15 +_ble_ctx_PWORDE=73 +_ble_ctx_PWORDR=72 +_ble_ctx_RDRF=19 +_ble_ctx_RDRD=20 +_ble_ctx_RDRD2=80 +_ble_ctx_RDRS=27 +_ble_ctx_VALX=23 +_ble_ctx_VALI=24 +_ble_ctx_VALR=65 +_ble_ctx_VALQ=66 +_ble_attr_COMMENT=25 +_ble_ctx_ARGVX=28 +_ble_ctx_ARGVI=29 +_ble_ctx_ARGVR=62 +_ble_ctx_CONDX=32 +_ble_ctx_CONDI=33 +_ble_ctx_CONDQ=67 +_ble_ctx_CASE=34 +_ble_ctx_CPATX=76 +_ble_ctx_CPATI=77 +_ble_ctx_CPATQ=79 +_ble_ctx_CPATX0=78 +_ble_ctx_PATN=30 +_ble_attr_GLOB=31 +_ble_ctx_BRAX=54 +_ble_attr_BRACE=55 +_ble_ctx_BRACE1=56 +_ble_ctx_BRACE2=57 +_ble_attr_TILDE=60 +_ble_ctx_FARGX1=16 +_ble_ctx_FARGI1=35 +_ble_ctx_FARGX2=36 +_ble_ctx_FARGI2=37 +_ble_ctx_FARGX3=58 +_ble_ctx_FARGI3=59 +_ble_ctx_FARGQ3=63 +_ble_ctx_SARGX1=48 +_ble_ctx_CARGX1=39 +_ble_ctx_CARGI1=40 +_ble_ctx_CARGQ1=64 +_ble_ctx_CARGX2=41 +_ble_ctx_CARGI2=42 +_ble_ctx_TARGX1=50 +_ble_ctx_TARGI1=51 +_ble_ctx_TARGX2=52 +_ble_ctx_TARGI2=53 +_ble_ctx_RDRH=44 +_ble_ctx_RDRI=45 +_ble_ctx_HERE0=46 +_ble_ctx_HERE1=47 +_ble_ctx_ARGEX=69 +_ble_ctx_ARGEI=70 +_ble_ctx_ARGER=71 +_ble_ctx_COARGX=74 +_ble_ctx_COARGI=75 +_ble_attr_CMD_BOLD=101 +_ble_attr_CMD_BUILTIN=102 +_ble_attr_CMD_ALIAS=103 +_ble_attr_CMD_FUNCTION=104 +_ble_attr_CMD_FILE=105 +_ble_attr_KEYWORD=106 +_ble_attr_KEYWORD_BEGIN=118 +_ble_attr_KEYWORD_END=119 +_ble_attr_KEYWORD_MID=120 +_ble_attr_CMD_JOBS=107 +_ble_attr_CMD_DIR=112 +_ble_attr_FILE_DIR=108 +_ble_attr_FILE_STICKY=124 +_ble_attr_FILE_LINK=109 +_ble_attr_FILE_ORPHAN=121 +_ble_attr_FILE_FILE=111 +_ble_attr_FILE_SETUID=122 +_ble_attr_FILE_SETGID=123 +_ble_attr_FILE_EXEC=110 +_ble_attr_FILE_FIFO=114 +_ble_attr_FILE_CHR=115 +_ble_attr_FILE_BLK=116 +_ble_attr_FILE_SOCK=117 +_ble_attr_FILE_WARN=113 +_ble_attr_FILE_URL=125 +_ble_attr_VAR_UNSET=126 +_ble_attr_VAR_EMPTY=127 +_ble_attr_VAR_NUMBER=128 +_ble_attr_VAR_EXPR=129 +_ble_attr_VAR_ARRAY=130 +_ble_attr_VAR_HASH=132 +_ble_attr_VAR_READONLY=131 +_ble_attr_VAR_TRANSFORM=133 +_ble_attr_VAR_EXPORT=134 +_ble_syntax_bash_ctx_names=( + [0]=_ble_ctx_UNSPECIFIED + [3]=_ble_ctx_ARGX + [18]=_ble_ctx_ARGX0 + [4]=_ble_ctx_ARGI + [61]=_ble_ctx_ARGQ + [1]=_ble_ctx_CMDX + [17]=_ble_ctx_CMDX1 + [49]=_ble_ctx_CMDXT + [26]=_ble_ctx_CMDXC + [43]=_ble_ctx_CMDXE + [38]=_ble_ctx_CMDXD0 + [68]=_ble_ctx_CMDXD + [13]=_ble_ctx_CMDXV + [2]=_ble_ctx_CMDI + [11]=_ble_ctx_VRHS + [5]=_ble_ctx_QUOT + [8]=_ble_ctx_EXPR + [6]=_ble_attr_ERR + [7]=_ble_attr_VAR + [9]=_ble_attr_QDEL + [81]=_ble_attr_QESC + [10]=_ble_attr_DEF + [12]=_ble_attr_DEL + [21]=_ble_attr_HISTX + [22]=_ble_attr_FUNCDEF + [14]=_ble_ctx_PARAM + [15]=_ble_ctx_PWORD + [73]=_ble_ctx_PWORDE + [72]=_ble_ctx_PWORDR + [19]=_ble_ctx_RDRF + [20]=_ble_ctx_RDRD + [80]=_ble_ctx_RDRD2 + [27]=_ble_ctx_RDRS + [23]=_ble_ctx_VALX + [24]=_ble_ctx_VALI + [65]=_ble_ctx_VALR + [66]=_ble_ctx_VALQ + [25]=_ble_attr_COMMENT + [28]=_ble_ctx_ARGVX + [29]=_ble_ctx_ARGVI + [62]=_ble_ctx_ARGVR + [32]=_ble_ctx_CONDX + [33]=_ble_ctx_CONDI + [67]=_ble_ctx_CONDQ + [34]=_ble_ctx_CASE + [76]=_ble_ctx_CPATX + [77]=_ble_ctx_CPATI + [79]=_ble_ctx_CPATQ + [78]=_ble_ctx_CPATX0 + [30]=_ble_ctx_PATN + [31]=_ble_attr_GLOB + [54]=_ble_ctx_BRAX + [55]=_ble_attr_BRACE + [56]=_ble_ctx_BRACE1 + [57]=_ble_ctx_BRACE2 + [60]=_ble_attr_TILDE + [16]=_ble_ctx_FARGX1 + [35]=_ble_ctx_FARGI1 + [36]=_ble_ctx_FARGX2 + [37]=_ble_ctx_FARGI2 + [58]=_ble_ctx_FARGX3 + [59]=_ble_ctx_FARGI3 + [63]=_ble_ctx_FARGQ3 + [48]=_ble_ctx_SARGX1 + [39]=_ble_ctx_CARGX1 + [40]=_ble_ctx_CARGI1 + [64]=_ble_ctx_CARGQ1 + [41]=_ble_ctx_CARGX2 + [42]=_ble_ctx_CARGI2 + [50]=_ble_ctx_TARGX1 + [51]=_ble_ctx_TARGI1 + [52]=_ble_ctx_TARGX2 + [53]=_ble_ctx_TARGI2 + [44]=_ble_ctx_RDRH + [45]=_ble_ctx_RDRI + [46]=_ble_ctx_HERE0 + [47]=_ble_ctx_HERE1 + [69]=_ble_ctx_ARGEX + [70]=_ble_ctx_ARGEI + [71]=_ble_ctx_ARGER + [74]=_ble_ctx_COARGX + [75]=_ble_ctx_COARGI + [101]=_ble_attr_CMD_BOLD + [102]=_ble_attr_CMD_BUILTIN + [103]=_ble_attr_CMD_ALIAS + [104]=_ble_attr_CMD_FUNCTION + [105]=_ble_attr_CMD_FILE + [106]=_ble_attr_KEYWORD + [118]=_ble_attr_KEYWORD_BEGIN + [119]=_ble_attr_KEYWORD_END + [120]=_ble_attr_KEYWORD_MID + [107]=_ble_attr_CMD_JOBS + [112]=_ble_attr_CMD_DIR + [108]=_ble_attr_FILE_DIR + [124]=_ble_attr_FILE_STICKY + [109]=_ble_attr_FILE_LINK + [121]=_ble_attr_FILE_ORPHAN + [111]=_ble_attr_FILE_FILE + [122]=_ble_attr_FILE_SETUID + [123]=_ble_attr_FILE_SETGID + [110]=_ble_attr_FILE_EXEC + [114]=_ble_attr_FILE_FIFO + [115]=_ble_attr_FILE_CHR + [116]=_ble_attr_FILE_BLK + [117]=_ble_attr_FILE_SOCK + [113]=_ble_attr_FILE_WARN + [125]=_ble_attr_FILE_URL + [126]=_ble_attr_VAR_UNSET + [127]=_ble_attr_VAR_EMPTY + [128]=_ble_attr_VAR_NUMBER + [129]=_ble_attr_VAR_EXPR + [130]=_ble_attr_VAR_ARRAY + [132]=_ble_attr_VAR_HASH + [131]=_ble_attr_VAR_READONLY + [133]=_ble_attr_VAR_TRANSFORM + [134]=_ble_attr_VAR_EXPORT +) +function ble/syntax/ctx#get-name { + ret=${_ble_syntax_bash_ctx_names[$1]#_ble_ctx_} +} +_BLE_SYNTAX_FCTX=() +_BLE_SYNTAX_FEND=() +function ble/syntax:text/ctx-unspecified { + ((i+=${#tail})) + return 0 +} +_BLE_SYNTAX_FCTX[_ble_ctx_UNSPECIFIED]=ble/syntax:text/ctx-unspecified +function ble/syntax:text/initialize-ctx { ctx=$_ble_ctx_UNSPECIFIED; } +function ble/syntax:text/initialize-vars { :; } +_ble_syntax_bash_RexSpaces=$'[ \t]+' +_ble_syntax_bash_RexIFSs="[$_ble_term_IFS]+" +_ble_syntax_bash_RexDelimiter="[$_ble_term_IFS;|&<>()]" +_ble_syntax_bash_RexRedirect='((\{[a-zA-Z_][a-zA-Z_0-9]*\}|[0-9]+)?(&?>>?|>[|&]|<[>&]?|<<[-<]?))[ ]*' +_ble_syntax_bash_chars=() +_ble_syntax_bashc_seed= +function ble/syntax:bash/cclass/update/reorder { + builtin eval "local a=\"\${$1}\"" + [[ $a == *']'* ]] && a="]${a//]}" + [[ $a == *'-'* ]] && a="${a//-}-" + builtin eval "$1=\$a" +} +function ble/syntax:bash/cclass/update { + local seed=$_ble_syntax_bash_histc12 + shopt -q extglob && seed=${seed}x + [[ $seed == "$_ble_syntax_bashc_seed" ]] && return 1 + _ble_syntax_bashc_seed=$seed + local key modified= + if [[ $_ble_syntax_bash_histc12 == '!^' ]]; then + for key in "${!_ble_syntax_bash_charsDef[@]}"; do + _ble_syntax_bash_chars[key]=${_ble_syntax_bash_charsDef[key]} + done + _ble_syntax_bashc_simple=$_ble_syntax_bash_chars_simpleDef + else + modified=1 + local histc1=${_ble_syntax_bash_histc12:0:1} + local histc2=${_ble_syntax_bash_histc12:1:1} + for key in "${!_ble_syntax_bash_charsFmt[@]}"; do + local a=${_ble_syntax_bash_charsFmt[key]} + a=${a//@h/"$histc1"} + a=${a//@q/"$histc2"} + _ble_syntax_bash_chars[key]=$a + done + local a=$_ble_syntax_bash_chars_simpleFmt + a=${a//@h/"$histc1"} + a=${a//@q/"$histc2"} + _ble_syntax_bashc_simple=$a + fi + if [[ $seed == *x ]]; then + local extglob='@+!' # *? は既に登録されている筈 + _ble_syntax_bash_chars[_ble_ctx_ARGI]=${_ble_syntax_bash_chars[_ble_ctx_ARGI]}$extglob + _ble_syntax_bash_chars[_ble_ctx_PATN]=${_ble_syntax_bash_chars[_ble_ctx_PATN]}$extglob + _ble_syntax_bash_chars[_ble_ctx_PWORD]=${_ble_syntax_bash_chars[_ble_ctx_PWORD]}$extglob + _ble_syntax_bash_chars[_ble_ctx_PWORDE]=${_ble_syntax_bash_chars[_ble_ctx_PWORDE]}$extglob + _ble_syntax_bash_chars[_ble_ctx_PWORDR]=${_ble_syntax_bash_chars[_ble_ctx_PWORDR]}$extglob + fi + if [[ $modified ]]; then + for key in "${!_ble_syntax_bash_chars[@]}"; do + ble/syntax:bash/cclass/update/reorder _ble_syntax_bash_chars[key] + done + ble/syntax:bash/cclass/update/reorder _ble_syntax_bashc_simple + fi + return 0 +} +_ble_syntax_bash_charsDef=() +_ble_syntax_bash_charsFmt=() +_ble_syntax_bash_chars_simpleDef= +_ble_syntax_bash_chars_simpleFmt= +function ble/syntax:bash/cclass/initialize { + local delimiters="$_ble_term_IFS;|&()<>" + local expansions="\$\"\`\\'" + local glob='[*?' + local tilde='~:' + _ble_syntax_bash_charsDef[_ble_ctx_ARGI]="$delimiters$expansions$glob{$tilde^!" + _ble_syntax_bash_charsDef[_ble_ctx_PATN]="$expansions$glob(|)<>{!" # <> はプロセス置換のため。 + _ble_syntax_bash_charsDef[_ble_ctx_QUOT]="\$\"\`\\!" # 文字列 "~" で特別な意味を持つのは $ ` \ " のみ。+履歴展開の ! も。 + _ble_syntax_bash_charsDef[_ble_ctx_EXPR]="][}()$expansions!" # ()[] は入れ子を数える為。} は ${var:ofs:len} の為。 + _ble_syntax_bash_charsDef[_ble_ctx_PWORD]="}$expansions$glob!" # パラメータ展開 ${~} + _ble_syntax_bash_charsDef[_ble_ctx_PWORDE]="}$expansions$glob!" # パラメータ展開 ${~} エラー + _ble_syntax_bash_charsDef[_ble_ctx_PWORDR]="}/$expansions$glob!" # パラメータ展開 ${~} 置換前 + _ble_syntax_bash_charsDef[_ble_ctx_RDRH]="$delimiters$expansions" + _ble_syntax_bash_charsFmt[_ble_ctx_ARGI]="$delimiters$expansions$glob{$tilde@q@h" + _ble_syntax_bash_charsFmt[_ble_ctx_PATN]="$expansions$glob(|)<>{@h" + _ble_syntax_bash_charsFmt[_ble_ctx_QUOT]="\$\"\`\\@h" + _ble_syntax_bash_charsFmt[_ble_ctx_EXPR]="][}()$expansions@h" + _ble_syntax_bash_charsFmt[_ble_ctx_PWORD]="}$expansions$glob@h" + _ble_syntax_bash_charsFmt[_ble_ctx_PWORDE]="}$expansions$glob@h" + _ble_syntax_bash_charsFmt[_ble_ctx_PWORDR]="}/$expansions$glob@h" + _ble_syntax_bash_charsFmt[_ble_ctx_RDRH]=${_ble_syntax_bash_charsDef[_ble_ctx_RDRH]} + _ble_syntax_bash_chars_simpleDef="$delimiters$expansions^!" + _ble_syntax_bash_chars_simpleFmt="$delimiters$expansions@q@h" + _ble_syntax_bash_histc12='!^' + ble/syntax:bash/cclass/update +} +ble/syntax:bash/cclass/initialize +_ble_syntax_bash_simple_rex_letter= +_ble_syntax_bash_simple_rex_param= +_ble_syntax_bash_simple_rex_bquot= +_ble_syntax_bash_simple_rex_squot= +_ble_syntax_bash_simple_rex_dquot= +_ble_syntax_bash_simple_rex_literal= +_ble_syntax_bash_simple_rex_element= +_ble_syntax_bash_simple_rex_word= +_ble_syntax_bash_simple_rex_open_word= +_ble_syntax_bash_simple_rex_open_dquot= +_ble_syntax_bash_simple_rex_open_squot= +_ble_syntax_bash_simple_rex_incomplete_word1= +_ble_syntax_bash_simple_rex_incomplete_word2= +_ble_syntax_bash_simple_rex_noglob_word1= +_ble_syntax_bash_simple_rex_noglob_word2= +function ble/syntax:bash/simple-word/update { + local q="'" + local letter='\[[!^]|[^'${_ble_syntax_bashc_simple}']' + local param1='\$([-*@#?$!0_]|[1-9][0-9]*|[a-zA-Z_][a-zA-Z_0-9]*)' + local param2='\$\{(#?[-*@#?$!0]|[#!]?([1-9][0-9]*|[a-zA-Z_][a-zA-Z_0-9]*))\}' # ${!!} ${!$} はエラーになる。履歴展開の所為? + local param=$param1'|'$param2 + local bquot='\\.' + local squot=$q'[^'$q']*'$q'|\$'$q'([^'$q'\]|\\.)*'$q + local dquot='\$?"([^'${_ble_syntax_bash_chars[_ble_ctx_QUOT]}']|\\.|'$param')*"' + _ble_syntax_bash_simple_rex_letter=$letter # 0 groups + _ble_syntax_bash_simple_rex_param=$param # 3 groups + _ble_syntax_bash_simple_rex_bquot=$bquot # 0 groups + _ble_syntax_bash_simple_rex_squot=$squot # 1 groups + _ble_syntax_bash_simple_rex_dquot=$dquot # 4 groups + _ble_syntax_bash_simple_rex_literal='^('$letter')+$' + _ble_syntax_bash_simple_rex_element='('$bquot'|'$squot'|'$dquot'|'$param'|'$letter')' + _ble_syntax_bash_simple_rex_word='^'$_ble_syntax_bash_simple_rex_element'+$' + local open_squot=$q'[^'$q']*|\$'$q'([^'$q'\]|\\.)*' + local open_dquot='\$?"([^'${_ble_syntax_bash_chars[_ble_ctx_QUOT]}']|\\.|'$param')*' + _ble_syntax_bash_simple_rex_open_word='^('$_ble_syntax_bash_simple_rex_element'*)(\\|'$open_squot'|'$open_dquot')$' + _ble_syntax_bash_simple_rex_open_squot=$open_squot + _ble_syntax_bash_simple_rex_open_dquot=$open_dquot + local letter1='\[[!^]|[^{'${_ble_syntax_bashc_simple}']' + local letter2='\[[!^]|[^'${_ble_syntax_bashc_simple}']' + _ble_syntax_bash_simple_rex_incomplete_word1='^('$bquot'|'$squot'|'$dquot'|'$param'|'$letter1')+' + _ble_syntax_bash_simple_rex_incomplete_word2='^(('$bquot'|'$squot'|'$dquot'|'$param'|'$letter2')*)(\\|'$open_squot'|'$open_dquot')?$' + local noglob_letter='[^[?*'${_ble_syntax_bashc_simple}']' + _ble_syntax_bash_simple_rex_noglob_word1='^('$bquot'|'$squot'|'$dquot'|'$noglob_letter')+$' + _ble_syntax_bash_simple_rex_noglob_word2='^('$bquot'|'$squot'|'$dquot'|'$param'|'$noglob_letter')+$' +} +ble/syntax:bash/simple-word/update +function ble/syntax:bash/simple-word/is-literal { + [[ $1 =~ $_ble_syntax_bash_simple_rex_literal ]] +} +function ble/syntax:bash/simple-word/is-simple { + [[ $1 =~ $_ble_syntax_bash_simple_rex_word ]] +} +function ble/syntax:bash/simple-word/is-simple-or-open-simple { + [[ $1 =~ $_ble_syntax_bash_simple_rex_word || $1 =~ $_ble_syntax_bash_simple_rex_open_word ]] +} +function ble/syntax:bash/simple-word/is-never-word { + ble/syntax:bash/simple-word/is-simple-or-open-simple && return 1 + local rex=${_ble_syntax_bash_simple_rex_word%'$'}'[ |&;<>()]|^[ |&;<>()]' + [[ $1 =~ $rex ]] +} +function ble/syntax:bash/simple-word/is-simple-noglob { + [[ $1 =~ $_ble_syntax_bash_simple_rex_noglob_word1 ]] && return 0 + if [[ $1 =~ $_ble_syntax_bash_simple_rex_noglob_word2 ]]; then + builtin eval -- "local expanded=$1" 2>/dev/null + local rex='[*?]|\[.+\]|[*?@+!]\(.*\)' + [[ $expanded =~ $rex ]] || return 0 + fi + return 1 +} +function ble/syntax:bash/simple-word/evaluate-last-brace-expansion { + local value=$1 + local bquot=$_ble_syntax_bash_simple_rex_bquot + local squot=$_ble_syntax_bash_simple_rex_squot + local dquot=$_ble_syntax_bash_simple_rex_dquot + local param=$_ble_syntax_bash_simple_rex_param + local letter='\[[!^]|[^{,}'${_ble_syntax_bashc_simple}']' + local symbol='[{,}]' + local rex_range_expansion='^(([-+]?[0-9]+)\.\.\.[-+]?[0-9]+|([a-zA-Z])\.\.[a-zA-Z])(\.\.[-+]?[0-9]+)?$' + local rex0='^('$bquot'|'$squot'|'$dquot'|'$param'|'$letter')+' + local stack; stack=() + local out= comma= index=0 iopen=0 no_brace_length=0 + while [[ $value ]]; do + if [[ $value =~ $rex0 ]]; then + local len=${#BASH_REMATCH} + ((index+=len,no_brace_length+=len)) + out=$out${value::len} + value=${value:len} + elif [[ $value == '{'* ]]; then + ((iopen=++index,no_brace_length=0)) + value=${value:1} + ble/array#push stack "$comma:$out" + out= comma= + elif ((${#stack[@]})) && [[ $value == '}'* ]]; then + ((++index)) + value=${value:1} + ble/array#pop stack + local out0=${ret#*:} comma0=${ret%%:*} + if [[ $comma ]]; then + ((iopen=index,no_brace_length=0)) + out=$out0$out + comma=$comma0 + elif [[ $out =~ $rex_range_expansion ]]; then + ((iopen=index,no_brace_length=0)) + out=$out0${2#+}$3 + comma=$comma0 + else + ((++no_brace_length)) + ble/array#push stack "$comma0:$out0" # cancel pop + out=$out'}' + fi + elif ((${#stack[@]})) && [[ $value == ','* ]]; then + ((iopen=++index,no_brace_length=0)) + value=${value:1} + out= comma=1 + else + ((++index,++no_brace_length)) + out=$out${value::1} + value=${value:1} + fi + done + while ((${#stack[@]})); do + ble/array#pop stack + local out0=${ret#*:} comma0=${ret%%:*} + out=$out0$out + done + ret=$out simple_ibrace=$iopen:$((${#out}-no_brace_length)) +} +function ble/syntax:bash/simple-word/reconstruct-incomplete-word { + local word=$1 + ret= simple_flags= simple_ibrace=0:0 + [[ $word ]] || return 0 + if [[ $word =~ $_ble_syntax_bash_simple_rex_incomplete_word1 ]]; then + ret=${word::${#BASH_REMATCH}} + word=${word:${#BASH_REMATCH}} + [[ $word ]] || return 0 + fi + if [[ $word =~ $_ble_syntax_bash_simple_rex_incomplete_word2 ]]; then + local out=$ret + local m_brace=${BASH_REMATCH[1]} + local m_quote=${word:${#m_brace}} + if [[ $m_brace ]]; then + ble/syntax:bash/simple-word/evaluate-last-brace-expansion "$m_brace" + simple_ibrace=$((${#out}+${simple_ibrace%:*})):$((${#out}+${simple_ibrace#*:})) + out=$out$ret + fi + if [[ $m_quote ]]; then + case $m_quote in + ('$"'*) out=$out$m_quote\" simple_flags=I ;; + ('"'*) out=$out$m_quote\" simple_flags=D ;; + ("$'"*) out=$out$m_quote\' simple_flags=E ;; + ("'"*) out=$out$m_quote\' simple_flags=S ;; + ('\') simple_flags=B ;; + (*) return 1 ;; + esac + fi + ret=$out + return 0 + fi + return 1 +} +function ble/syntax:bash/simple-word/extract-parameter-names { + ret=() + local letter=$_ble_syntax_bash_simple_rex_letter + local bquot=$_ble_syntax_bash_simple_rex_bquot + local squot=$_ble_syntax_bash_simple_rex_squot + local dquot=$_ble_syntax_bash_simple_rex_dquot + local param=$_ble_syntax_bash_simple_rex_param + local value=$1 + local rex0='^('$letter'|'$bquot'|'$squot')+' + local rex1='^('$dquot')' + local rex2='^('$param')' + while [[ $value ]]; do + [[ $value =~ $rex0 ]] && value=${value:${#BASH_REMATCH}} + if [[ $value =~ $rex1 ]]; then + value=${value:${#BASH_REMATCH}} + ble/syntax:bash/simple-word/extract-parameter-names/.process-dquot "$BASH_REMATCH" + fi + [[ $value =~ $rex2 ]] || break + value=${value:${#BASH_REMATCH}} + local var=${BASH_REMATCH[2]}${BASH_REMATCH[3]} + [[ $var == [_a-zA-Z]* ]] && ble/array#push ret "$var" + done +} +function ble/syntax:bash/simple-word/extract-parameter-names/.process-dquot { + local value=$1 + if [[ $value == '$"'*'"' ]]; then + value=${value:2:${#value}-3} + elif [[ $value == '"'*'"' ]]; then + value=${value:1:${#value}-2} + else + return 0 + fi + local rex0='^([^'${_ble_syntax_bash_chars[_ble_ctx_QUOT]}']|\\.)+' + local rex2='^('$param')' + while [[ $value ]]; do + [[ $value =~ $rex0 ]] && value=${value:${#BASH_REMATCH}} + [[ $value =~ $rex2 ]] || break + value=${value:${#BASH_REMATCH}} + local var=${BASH_REMATCH[2]}${BASH_REMATCH[3]} + [[ $var == [_a-zA-Z]* ]] && ble/array#push ret "$var" + done +} +function ble/syntax:bash/simple-word/eval/.set-result { __ble_ret=("$@"); } +function ble/syntax:bash/simple-word/eval/.print-result { + if (($#>=1000)) && [[ $OSTYPE != cygwin ]]; then + if ((_ble_bash>=50200)); then + printf '%s\0' "$@" >| "$__ble_simple_word_tmpfile" + ble/util/print 'ble/util/readarray -d "" __ble_ret < "$__ble_simple_word_tmpfile"' + return 0 + elif ((_ble_bash>=40000)); then + ret=("$@") + ble/util/writearray --nlfix ret >| "$__ble_simple_word_tmpfile" + ble/util/print 'ble/util/readarray --nlfix __ble_ret < "$__ble_simple_word_tmpfile"' + return 0 + fi + fi + local ret; ble/string#quote-words "$@" + ble/util/print "__ble_ret=($ret)" +} +function ble/syntax:bash/simple-word/eval/.impl { + local __ble_word=$1 __ble_opts=$2 __ble_flags= + local -a ret=() + ble/syntax:bash/simple-word/extract-parameter-names "$__ble_word" + if ((${#ret[@]})); then + local __ble_defs + ble/util/assign __ble_defs 'ble/util/print-global-definitions --hidden-only "${ret[@]}"' + builtin eval -- "$__ble_defs" &>/dev/null # 読み取り専用の変数のこともある + fi + if [[ $- != *f* ]] && ! ble/syntax:bash/simple-word/is-simple-noglob "$1"; then + if [[ :$__ble_opts: == *:noglob:* ]]; then + set -f + __ble_flags=f + elif ble/util/is-cygwin-slow-glob "$1"; then # Note: #D1168 + if shopt -q failglob &>/dev/null; then + __ble_ret=() + return 1 + elif shopt -q nullglob &>/dev/null; then + __ble_ret=() + return 0 + else + set -f + __ble_flags=f + fi + elif [[ :$__ble_opts: == *:stopcheck:* ]]; then + ble/decode/has-input && return 148 + if ((_ble_bash>=40000)); then + __ble_flags=s + elif shopt -q globstar &>/dev/null; then + if builtin eval "[[ $__ble_word == *'**'* ]]"; then + [[ :$__ble_opts: == *:timeout=*:* ]] && return 142 + return 148 + fi + fi + fi + fi + __ble_ret=() + if [[ $__ble_flags == *s* ]]; then + local __ble_sync_command="ble/syntax:bash/simple-word/eval/.print-result $__ble_word" + local __ble_sync_opts=progressive-weight + local __ble_sync_weight=$bleopt_syntax_eval_polling_interval + local __ble_sync_timeout=$_ble_syntax_bash_simple_eval_timeout + if [[ $_ble_syntax_bash_simple_eval_timeout_carry ]]; then + __ble_sync_timeout=0 + elif local __ble_rex=':timeout=([^:]*):'; [[ :$__ble_opts: =~ $__ble_rex ]]; then + __ble_sync_timeout=${BASH_REMATCH[1]} + fi + [[ $__ble_sync_timeout ]] && + __ble_sync_opts=$__ble_sync_opts:timeout=$((__ble_sync_timeout)) + local _ble_local_tmpfile; ble/util/assign/.mktmp + local __ble_simple_word_tmpfile=$_ble_local_tmpfile + local __ble_script + ble/util/assign __ble_script 'ble/util/conditional-sync "$__ble_sync_command" "" "$__ble_sync_weight" "$__ble_sync_opts"' &>/dev/null; local ext=$? + builtin eval -- "$__ble_script" + ble/util/assign/.rmtmp + else + builtin eval "ble/syntax:bash/simple-word/eval/.set-result $__ble_word" &>/dev/null; local ext=$? + builtin eval : # Note: bash 3.1/3.2 eval バグ対策 (#D1132) + fi + [[ $__ble_flags == *f* ]] && set +f + return "$ext" +} +_ble_syntax_bash_simple_eval_hash= +function ble/syntax:bash/simple-word/eval/.cache-clear { + ble/gdict#clear _ble_syntax_bash_simple_eval + ble/gdict#clear _ble_syntax_bash_simple_eval_full +} +function ble/syntax:bash/simple-word/eval/.cache-update { + local hash=$-:$BASHOPTS:$_ble_edit_lineno:$_ble_textarea_version:$PWD + if [[ $hash != "$_ble_syntax_bash_simple_eval_hash" ]]; then + _ble_syntax_bash_simple_eval_hash=$hash + ble/syntax:bash/simple-word/eval/.cache-clear + fi +} +function ble/syntax:bash/simple-word/eval/.cache-save { + ((ext==148||ext==142)) && return 0 + local ret; ble/string#quote-words "$3" + ble/gdict#set _ble_syntax_bash_simple_eval "$1" "ext=$2 count=$(($#-2)) ret=$ret" + local ret; ble/string#quote-words "${@:3}" + ble/gdict#set _ble_syntax_bash_simple_eval_full "$1" "ext=$2 count=$(($#-2)) ret=($ret)" +} +function ble/syntax:bash/simple-word/eval/.cache-load { + ext= ret= + if [[ :$2: == *:single:* ]]; then + ble/gdict#get _ble_syntax_bash_simple_eval "$1" || return 1 + else + ble/gdict#get _ble_syntax_bash_simple_eval_full "$1" || return 1 + fi + builtin eval -- "$ret" + return 0 +} +_ble_syntax_bash_simple_eval_timeout= +_ble_syntax_bash_simple_eval_timeout_carry= +function ble/syntax:bash/simple-word/eval { + [[ :$2: != *:count:* ]] && local count + if [[ :$2: == *:cached:* && :$2: != *:noglob:* ]]; then + ble/syntax:bash/simple-word/eval/.cache-update + local ext; ble/syntax:bash/simple-word/eval/.cache-load "$1" "$2" && return "$ext" + fi + local __ble_ret + ble/syntax:bash/simple-word/eval/.impl "$1" "$2"; local ext=$? + ret=("${__ble_ret[@]}") + count=${#ret[@]} + if [[ :$2: == *:cached:* && :$2: != *:noglob:* ]]; then + ble/syntax:bash/simple-word/eval/.cache-save "$1" "$ext" "${ret[@]}" + fi + if ((ext==142)); then + [[ :$2: == *:timeout-carry:* ]] && + _ble_syntax_bash_simple_eval_timeout_carry=1 + if [[ :$2: == *:retry-noglob-on-timeout:* ]]; then + ble/syntax:bash/simple-word/eval "$1" "$2:noglob" + return "$?" + fi + fi + return "$ext" +} +function ble/syntax:bash/simple-word/.get-rex_element { + local sep=$1 + local param=$_ble_syntax_bash_simple_rex_param + local bquot=$_ble_syntax_bash_simple_rex_bquot + local squot=$_ble_syntax_bash_simple_rex_squot + local dquot=$_ble_syntax_bash_simple_rex_dquot + local letter1='\[[!^]|[^'$sep$_ble_syntax_bashc_simple']' + rex_element='('$bquot'|'$squot'|'$dquot'|'$param'|'$letter1')+' +} +function ble/syntax:bash/simple-word/evaluate-path-spec { + local word=$1 sep=${2:-'/:='} opts=$3 + ret=() spec=() path=() + [[ $word ]] || return 0 + local eval_opts=$opts notilde= + [[ :$opts: == *:notilde:* ]] && notilde=\'\' # チルダ展開の抑制 + local rex_element; ble/syntax:bash/simple-word/.get-rex_element "$sep" + local rex='^['$sep']?'$rex_element'|^['$sep']' + [[ :$opts: == *:after-sep:* ]] && + local rex='^'$rex_element'['$sep']?|^['$sep']' + local tail=$word s= p= ext=0 + while [[ $tail =~ $rex ]]; do + local rematch=$BASH_REMATCH + s=$s$rematch + ble/syntax:bash/simple-word/eval "$notilde$s" "$eval_opts"; ext=$? + ((ext==148||ext==142)) && return "$ext" + p=$ret + tail=${tail:${#rematch}} + ble/array#push spec "$s" + ble/array#push path "$p" + done + [[ $tail ]] && return 1 + ((ext)) && return "$ext" + return 0 +} +function ble/syntax:bash/simple-word/detect-separated-path { + local word=$1 sep=${2:-':'} opts=$3 + [[ $word ]] || return 1 + local rex_url='^[a-z]+://' + [[ :$opts: == *:url:* && $word =~ $rex_url ]] && return 1 + local eval_opts=$opts notilde= + [[ :$opts: == *:notilde:* ]] && notilde=\'\' # チルダ展開の抑制 + local rex_element + ble/syntax:bash/simple-word/.get-rex_element / + local rex='^'$rex_element'/?|^/' + local tail=$word head= + while [[ $tail =~ $rex ]]; do + local rematch=$BASH_REMATCH + ble/syntax:bash/simple-word/locate-filename/.exists "$notilde$head$rematch"; local ext=$? + ((ext==148)) && return 148 + ((ext==0)) || break + head=$head$rematch + tail=${tail:${#rematch}} + done + ret= + local i + for ((i=0;i<${#sep};i++)); do + local sep1=${sep:i:1} + ble/syntax:bash/simple-word/.get-rex_element "$sep1" + local rex_nocolon='^('$rex_element')?$' + local rex_hascolon='^('$rex_element')?['$sep1']' + [[ $head =~ $rex_nocolon && $tail =~ $rex_hascolon ]] && ret=$ret$sep1 + done + [[ $ret ]] +} +function ble/syntax:bash/simple-word/locate-filename/.exists { + local word=$1 ret + ble/syntax:bash/simple-word/eval "$word" "$eval_opts" || return "$?" + local path=$ret + if [[ ( $OSTYPE == cygwin || $OSTYPE == msys ) && $path == //* ]]; then + [[ $path == // ]] + else + [[ -e $path || -h $path ]] + fi || [[ :$opts: == *:url:* && $path =~ $rex_url ]] +} +function ble/syntax:bash/simple-word/locate-filename { + local word=$1 sep=${2:-':='} opts=$3 + ret=0 + [[ $word ]] || return 0 + local eval_opts=$opts + local rex_element; ble/syntax:bash/simple-word/.get-rex_element "$sep" + local rex='^'$rex_element'['$sep']|^['$sep']' + local rex_url='^[a-z]+://' + local -a seppos=() + local tail=$word p=0 + while [[ $tail =~ $rex ]]; do + ((p+=${#BASH_REMATCH})) + tail=${tail:${#BASH_REMATCH}} + ble/array#push seppos $((p-1)) + done + ble/syntax:bash/simple-word/is-simple "$tail" && + ble/array#push seppos $((p+${#tail})) + local -a out=() + for ((i=0;i<${#seppos[@]};i++)); do + local j0=$i + [[ :$opts: == *:greedy:* ]] && j0=${#seppos[@]}-1 + for ((j=j0;j>=i;j--)); do + local f1=0 f2=${seppos[j]} + ((i)) && ((f1=seppos[i-1]+1)) + if ((j>i)); then + ble/syntax:bash/simple-word/locate-filename/.exists "${word:f1:f2-f1}" "$opts"; local ext=$? + ((ext==148)) && return 148 + if ((ext==0)); then + ble/array#push out "$f1" "$f2" + ((i=j)) + fi + else + if [[ :$opts: != *:exists:* ]] || + { ble/syntax:bash/simple-word/locate-filename/.exists "${word:f1:f2-f1}" "$opts" + local ext=$?; ((ext==148)) && return 148; ((ext==0)); }; then + ble/array#push out "$f1" "$f2" + fi + fi + done + done + ret=("${out[@]}") + return 0 +} +function ble/syntax:bash/simple-word#break-word { + local word=$1 sep=${2:-':='} + if [[ ! $word ]]; then + ret=('') + return 0 + fi + sep=${sep//[\"\'\$\`]} + local rex_element; ble/syntax:bash/simple-word/.get-rex_element "$sep" + local rex='^('$rex_element')?['$sep']+' + local -a out=() + local tail=$word p=0 + while [[ $tail =~ $rex ]]; do + local rematch1=${BASH_REMATCH[1]} + ble/array#push out "$rematch1" + ble/array#push out "${BASH_REMATCH:${#rematch1}}" + tail=${tail:${#BASH_REMATCH}} + done + ble/array#push out "$tail" + ret=("${out[@]}") + return 0 +} +function ble/syntax:bash/initialize-ctx { + ctx=$_ble_ctx_CMDX # _ble_ctx_CMDX が ble/syntax:bash の最初の文脈 +} +function ble/syntax:bash/initialize-vars { + local histc12 + if [[ ${histchars+set} ]]; then + histc12=${histchars::2} + else + histc12='!^' + fi + _ble_syntax_bash_histc12=$histc12 + if ble/syntax:bash/cclass/update; then + ble/syntax:bash/simple-word/update + fi + local histstop=$' \t\n=' + shopt -q extglob && histstop="$histstop(" + _ble_syntax_bash_histstop=$histstop +} +function ble/syntax/highlight/vartype { + if [[ ! $bleopt_highlight_variable ]]; then + ret=$_ble_attr_VAR + return 0 + fi + local name=$1 opts=$2 tail=$3 rex='^-?[0-9]+(#[0-9a-zA-Z@_]*)?$' + local attr; ble/variable#get-attr "$name" + if [[ ${!name+set} || $attr == *[aA]* ]]; then + if [[ ${!name-} && :$opts: == *:expr:* && ! ( ${!name} =~ $rex ) ]]; then + ret=$_ble_attr_VAR_EXPR + elif [[ ${!name+set} && $attr == *x* ]]; then + ret=$_ble_attr_VAR_EXPORT + elif [[ $attr == *a* ]]; then + ret=$_ble_attr_VAR_ARRAY + elif [[ $attr == *A* ]]; then + ret=$_ble_attr_VAR_HASH + elif [[ $attr == *r* ]]; then + ret=$_ble_attr_VAR_READONLY + elif [[ $attr == *i* ]]; then + ret=$_ble_attr_VAR_NUMBER + elif [[ $attr == *[luc]* ]]; then + ret=$_ble_attr_VAR_TRANSFORM + elif [[ ! ${!name} ]]; then + ret=$_ble_attr_VAR_EMPTY + else + ret=$_ble_attr_VAR + fi + else + if [[ :$opts: == *:readvar:* && $_ble_bash_set == *u* ]]; then + if [[ ! $tail ]] || { + local rex='^:?[-+?=]' + [[ $tail == :* ]] && lookahead=2 + ! [[ $tail =~ $rex ]]; } + then + ret=$_ble_attr_ERR + return 0 + fi + fi + ret=$_ble_attr_VAR_UNSET + fi +} +function ble/syntax:bash/check-plain-with-escape { + local rex='^('$1'|\\.)' is_quote=$2 + [[ $tail =~ $rex ]] || return 1 + if [[ $BASH_REMATCH == '\'? && + ( ! $is_quote || $BASH_REMATCH == '\'[$'\\`$\n"'] ) ]]; then + ((_ble_syntax_attr[i]=_ble_attr_QESC)) + else + ((_ble_syntax_attr[i]=ctx)) + fi + ((i+=${#BASH_REMATCH})) + return 0 +} +function ble/syntax:bash/check-dollar { + [[ $tail == '$'* ]] || return 1 + local rex + if [[ $tail == '${'* ]]; then + local rex1='^(\$\{#)([-*@#?$!0]\}?|[1-9][0-9]*\}?|[a-zA-Z_][a-zA-Z_0-9]*[[}]?)' + local rex2='^(\$\{!?)([-*@#?$!0]|[1-9][0-9]*|[a-zA-Z_][a-zA-Z_0-9]*\[?)' + if + [[ $tail =~ $rex1 ]] && { + [[ ${BASH_REMATCH[2]} == *['[}'] || $BASH_REMATCH == "$tail" ]] || + { ble/syntax/parse/set-lookahead $((${#BASH_REMATCH}+1)); false; } } || + [[ $tail =~ $rex2 ]] + then + local rematch1=${BASH_REMATCH[1]} + local rematch2=${BASH_REMATCH[2]} + local varname=${rematch2%['[}']} + local ntype='${' + if ((ctx==_ble_ctx_QUOT)); then + ntype='"${' + elif ((ctx==_ble_ctx_PWORD||ctx==_ble_ctx_PWORDE||ctx==_ble_ctx_PWORDR||ctx==_ble_ctx_EXPR)); then + local ntype2; ble/syntax/parse/nest-type -v ntype2 + [[ $ntype2 == '"${' ]] && ntype='"${' + fi + local ret lookahead= tail2=${tail:${#rematch1}+${#varname}} + ble/syntax/highlight/vartype "$varname" readvar "$tail2"; local attr=$ret + ble/syntax/parse/nest-push "$_ble_ctx_PARAM" "$ntype" + ((_ble_syntax_attr[i]=ctx, + i+=${#rematch1}, + _ble_syntax_attr[i]=attr, + i+=${#varname})) + [[ $lookahead ]] && ble/syntax/parse/set-lookahead "$lookahead" + if rex='^\$\{![a-zA-Z_][a-zA-Z_0-9]*[*@]\}?'; [[ $tail =~ $rex ]]; then + ble/syntax/parse/set-lookahead 2 + if [[ $BASH_REMATCH == *'}' ]]; then + ((i++,ctx=_ble_ctx_PWORDE)) + fi + elif [[ $rematch2 == *'[' ]]; then + ble/syntax/parse/nest-push "$_ble_ctx_EXPR" 'v[' + ((_ble_syntax_attr[i++]=_ble_ctx_EXPR)) + fi + return 0 + else + ((_ble_syntax_attr[i]=_ble_attr_ERR,i+=2)) + return 0 + fi + elif [[ $tail == '$(('* ]]; then + ((_ble_syntax_attr[i]=_ble_ctx_PARAM)) + ble/syntax/parse/nest-push "$_ble_ctx_EXPR" '$((' + ((i+=3)) + return 0 + elif [[ $tail == '$['* ]]; then + ((_ble_syntax_attr[i]=_ble_ctx_PARAM)) + ble/syntax/parse/nest-push "$_ble_ctx_EXPR" '$[' + ((i+=2)) + return 0 + elif [[ $tail == '$('* ]]; then + ((_ble_syntax_attr[i]=_ble_ctx_PARAM)) + ble/syntax/parse/nest-push "$_ble_ctx_CMDX" '$(' + ((i+=2)) + return 0 + elif rex='^\$([-*@#?$!0_]|[1-9]|[a-zA-Z_][a-zA-Z_0-9]*)' && [[ $tail =~ $rex ]]; then + local rematch=$BASH_REMATCH rematch1=${BASH_REMATCH[1]} + local ret; ble/syntax/highlight/vartype "$rematch1" readvar + ((_ble_syntax_attr[i]=_ble_ctx_PARAM, + _ble_syntax_attr[i+1]=ret, + i+=${#rematch})) + return 0 + else + ((_ble_syntax_attr[i++]=ctx)) + return 0 + fi +} +function ble/syntax:bash/check-quotes { + local rex aqdel=$_ble_attr_QDEL aquot=$_ble_ctx_QUOT + if ((ctx==_ble_ctx_EXPR)); then + local ntype + ble/syntax/parse/nest-type + if [[ $ntype == '${' || $ntype == '$[' || $ntype == '$((' || $ntype == 'NQ(' ]]; then + ((aqdel=_ble_attr_ERR,aquot=_ble_ctx_EXPR)) + elif [[ $ntype == '"${' ]] && ! { [[ $tail == '$'[\'\"]* ]] && shopt -q extquote; }; then + ((aqdel=_ble_attr_ERR,aquot=_ble_ctx_EXPR)) + fi + elif ((ctx==_ble_ctx_PWORD||ctx==_ble_ctx_PWORDE||ctx==_ble_ctx_PWORDR)); then + if [[ $tail == '$'[\'\"]* ]] && ! shopt -q extquote; then + local ntype + ble/syntax/parse/nest-type + if [[ $ntype == '"${' ]]; then + ((aqdel=ctx,aquot=ctx)) + fi + fi + fi + if rex='^`([^`\]|\\(.|$))*(`?)|^'\''[^'\'']*('\''?)' && [[ $tail =~ $rex ]]; then + ((_ble_syntax_attr[i]=aqdel, + _ble_syntax_attr[i+1]=aquot, + i+=${#BASH_REMATCH}, + _ble_syntax_attr[i-1]=${#BASH_REMATCH[3]}||${#BASH_REMATCH[4]}?aqdel:_ble_attr_ERR)) + return 0 + fi + if ((ctx!=_ble_ctx_QUOT)); then + if rex='^(\$?")([^'"${_ble_syntax_bash_chars[_ble_ctx_QUOT]}"']*)("?)' && [[ $tail =~ $rex ]]; then + local rematch1=${BASH_REMATCH[1]} # for bash-3.1 ${#arr[n]} bug + if [[ ${BASH_REMATCH[3]} ]]; then + ((_ble_syntax_attr[i]=aqdel, + _ble_syntax_attr[i+${#rematch1}]=aquot, + i+=${#BASH_REMATCH}, + _ble_syntax_attr[i-1]=aqdel)) + else + ble/syntax/parse/nest-push "$_ble_ctx_QUOT" + if (((ctx==_ble_ctx_PWORD||ctx==_ble_ctx_PWORDE||ctx==_ble_ctx_PWORDR)&&aqdel!=_ble_attr_QDEL)); then + ((_ble_syntax_attr[i]=aqdel, + _ble_syntax_attr[i+${#rematch1}-1]=_ble_attr_QDEL, + _ble_syntax_attr[i+${#rematch1}]=_ble_ctx_QUOT, + i+=${#BASH_REMATCH})) + else + ((_ble_syntax_attr[i]=aqdel, + _ble_syntax_attr[i+${#rematch1}]=_ble_ctx_QUOT, + i+=${#BASH_REMATCH})) + fi + fi + return 0 + elif rex='^\$'\''(([^'\''\]|\\(.|$))*)('\''?)' && [[ $tail =~ $rex ]]; then + ((_ble_syntax_attr[i]=aqdel,i+=2)) + local t=${BASH_REMATCH[1]} rematch4=${BASH_REMATCH[4]} + local rex='\\[abefnrtvE"'\''\?]|\\[0-7]{1,3}|\\c.|\\x[0-9a-fA-F]{1,2}' + ((_ble_bash>=40200)) && rex=$rex'|\\u[0-9a-fA-F]{1,4}|\\U[0-9a-fA-F]{1,8}' + local rex='^([^'\''\]*)('$rex'|(\\.))' + while [[ $t =~ $rex ]]; do + local m1=${BASH_REMATCH[1]} m2=${BASH_REMATCH[2]} + [[ $m1 ]] && ((_ble_syntax_attr[i]=aquot,i+=${#m1})) + if [[ ${BASH_REMATCH[3]} ]]; then + ((_ble_syntax_attr[i]=aquot)) + else + ((_ble_syntax_attr[i]=_ble_attr_QESC)) + fi + ((i+=${#m2})) + t=${t:${#BASH_REMATCH}} + done + [[ $t ]] && ((_ble_syntax_attr[i]=aquot,i+=${#t})) + if [[ $rematch4 ]]; then + ((_ble_syntax_attr[i++]=aqdel)) + else + ((_ble_syntax_attr[i-1]=_ble_attr_ERR)) + fi + return 0 + fi + fi + return 1 +} +function ble/syntax:bash/check-process-subst { + if [[ $tail == ['<>']'('* ]]; then + ble/syntax/parse/nest-push "$_ble_ctx_CMDX" '(' + ((_ble_syntax_attr[i]=_ble_attr_DEL,i+=2)) + return 0 + fi + return 1 +} +function ble/syntax:bash/check-comment { + if shopt -q interactive_comments; then + if ((wbegin<0||wbegin==i)) && local rex=$'^#[^\n]*' && [[ $tail =~ $rex ]]; then + ((_ble_syntax_attr[i]=_ble_attr_COMMENT, + i+=${#BASH_REMATCH})) + return 0 + fi + fi + return 1 +} +function ble/syntax:bash/check-glob { + [[ $tail == ['[?*@+!()|']* ]] || return 1 + local ntype= force_attr= + if ((ctx==_ble_ctx_VRHS||ctx==_ble_ctx_ARGVR||ctx==_ble_ctx_ARGER||ctx==_ble_ctx_VALR||ctx==_ble_ctx_RDRS)); then + force_attr=$ctx + ntype="glob_attr=$force_attr" + elif ((ctx==_ble_ctx_FARGX1||ctx==_ble_ctx_FARGI1)); then + force_attr=$_ble_attr_ERR + ntype="glob_attr=$force_attr" + elif ((ctx==_ble_ctx_PWORD||ctx==_ble_ctx_PWORDE||ctx==_ble_ctx_PWORDR)); then + ntype="glob_ctx=$ctx" + elif ((ctx==_ble_ctx_PATN||ctx==_ble_ctx_BRAX)); then + ble/syntax/parse/nest-type + local exit_attr= + if [[ $ntype == glob_attr=* ]]; then + force_attr=${ntype#*=} + exit_attr=$force_attr + elif ((ctx==_ble_ctx_BRAX)); then + force_attr=$ctx + ntype="glob_attr=$force_attr" + elif ((ctx==_ble_ctx_PATN)); then + ((exit_attr=_ble_syntax_attr[inest])) + [[ $ntype != glob_ctx=* ]] && ntype= + else + ntype= + fi + elif [[ $1 == assign ]]; then + ntype='a[' + fi + if [[ $tail == ['?*@+!']'('* ]] && shopt -q extglob; then + ble/syntax/parse/nest-push "$_ble_ctx_PATN" "$ntype" + ((_ble_syntax_attr[i]=${force_attr:-_ble_attr_GLOB},i+=2)) + return 0 + fi + local histc1=${_ble_syntax_bash_histc12::1} + [[ $histc1 && $tail == "$histc1"* ]] && return 1 + if [[ $tail == '['* ]]; then + if ((ctx==_ble_ctx_BRAX)); then + ((_ble_syntax_attr[i++]=force_attr)) + [[ $tail == '[!'* ]] && ((i++)) + return 0 + fi + ble/syntax/parse/nest-push "$_ble_ctx_BRAX" "$ntype" + ((_ble_syntax_attr[i++]=${force_attr:-_ble_attr_GLOB})) + [[ $tail == '[!'* ]] && ((i++)) + if [[ ${text:i:1} == ']' ]]; then + ((_ble_syntax_attr[i++]=${force_attr:-_ble_ctx_BRAX})) + elif [[ ${text:i:1} == '[' ]]; then + if [[ ${text:i+1:1} == [:=.] ]]; then + ble/syntax/parse/set-lookahead 2 + else + ((_ble_syntax_attr[i++]=${force_attr:-_ble_ctx_BRAX})) + [[ ${text:i:1} == '!'* ]] && ((i++)) + fi + fi + return 0 + elif [[ $tail == ['?*']* ]]; then + ((_ble_syntax_attr[i++]=${force_attr:-_ble_attr_GLOB})) + return 0 + elif [[ $tail == ['@+!']* ]]; then + ((_ble_syntax_attr[i++]=${force_attr:-ctx})) + return 0 + elif ((ctx==_ble_ctx_PATN||ctx==_ble_ctx_BRAX)); then + if [[ $tail == '('* ]]; then + ble/syntax/parse/nest-push "$_ble_ctx_PATN" "$ntype" + ((_ble_syntax_attr[i++]=${force_attr:-ctx})) + return 0 + elif [[ $tail == ')'* ]]; then + if ((ctx==_ble_ctx_PATN)); then + ((_ble_syntax_attr[i++]=exit_attr)) + ble/syntax/parse/nest-pop + else + ((_ble_syntax_attr[i++]=${force_attr:-ctx})) + fi + return 0 + elif [[ $tail == '|'* ]]; then + ((_ble_syntax_attr[i++]=${force_attr:-_ble_attr_GLOB})) + return 0 + fi + fi + return 1 +} +_ble_syntax_bash_histexpand_RexWord= +_ble_syntax_bash_histexpand_RexMods= +_ble_syntax_bash_histexpand_RexEventDef= +_ble_syntax_bash_histexpand_RexQuicksubDef= +_ble_syntax_bash_histexpand_RexEventFmt= +_ble_syntax_bash_histexpand_RexQuicksubFmt= +function ble/syntax:bash/check-history-expansion/.initialize { + local spaces=$_ble_term_IFS nl=$'\n' + local rex_event='-?[0-9]+|[!#]|[^-$^*%:'$spaces'=?!#;&|<>()]+|\?[^?'$nl']*\??' + _ble_syntax_bash_histexpand_RexEventDef='^!('$rex_event')' + local rex_word1='([0-9]+|[$%^])' + local rex_wordsA=':('$rex_word1'?-'$rex_word1'?|\*|'$rex_word1'\*?)' + local rex_wordsB='([$%^]?-'$rex_word1'?|\*|[$^%][*-]?)' + _ble_syntax_bash_histexpand_RexWord='('$rex_wordsA'|'$rex_wordsB')?' + local rex_modifier=':[htrepqx]|:[gGa]?&|:[gGa]?s(/([^\/]|\\.)*){0,2}(/|$)' + _ble_syntax_bash_histexpand_RexMods='('$rex_modifier')*' + _ble_syntax_bash_histexpand_RexQuicksubDef='\^([^^\]|\\.)*\^([^^\]|\\.)*\^' + _ble_syntax_bash_histexpand_RexQuicksubFmt='@A([^@C\]|\\.)*@A([^@C\]|\\.)*@A' + _ble_syntax_bash_histexpand_RexEventFmt='^@A('$rex_event'|@A)' +} +ble/syntax:bash/check-history-expansion/.initialize +function ble/syntax:bash/check-history-expansion/.initialize-event { + local histc1=${_ble_syntax_bash_histc12::1} + if [[ $histc1 == '!' ]]; then + rex_event=$_ble_syntax_bash_histexpand_RexEventDef + else + local A="[$histc1]" + [[ $histc1 == '^' ]] && A='\^' + rex_event=$_ble_syntax_bash_histexpand_RexEventFmt + rex_event=${rex_event//@A/"$A"} + fi +} +function ble/syntax:bash/check-history-expansion/.initialize-quicksub { + local histc2=${_ble_syntax_bash_histc12:1:1} + if [[ $histc2 == '^' ]]; then + rex_quicksub=$_ble_syntax_bash_histexpand_RexQuicksubDef + else + rex_quicksub=$_ble_syntax_bash_histexpand_RexQuicksubFmt + rex_quicksub=${rex_quicksub//@A/"[$histc2]"} + rex_quicksub=${rex_quicksub//@C/"$histc2"} + fi +} +function ble/syntax:bash/check-history-expansion/.check-modifiers { + [[ ${text:i} =~ $_ble_syntax_bash_histexpand_RexMods ]] && + ((i+=${#BASH_REMATCH})) + if local rex='^:[gGa]?s(.)'; [[ ${text:i} =~ $rex ]]; then + local del=${BASH_REMATCH[1]} + local A="[$del]" B="[^$del]" + [[ $del == '^' || $del == ']' ]] && A='\'$del + [[ $del != '\' ]] && B=$B'|\\.' + local rex_substitute='^:[gGa]?s('$A'('$B')*){0,2}('$A'|$)' + if [[ ${text:i} =~ $rex_substitute ]]; then + ((i+=${#BASH_REMATCH})) + ble/syntax:bash/check-history-expansion/.check-modifiers + return 0 + fi + fi + if [[ ${text:i} == ':'[gGa]* ]]; then + ((_ble_syntax_attr[i+1]=_ble_attr_ERR,i+=2)) + elif [[ ${text:i} == ':'* ]]; then + ((_ble_syntax_attr[i]=_ble_attr_ERR,i++)) + fi +} +function ble/syntax:bash/check-history-expansion { + [[ -o histexpand ]] || return 1 + local histc1=${_ble_syntax_bash_histc12:0:1} + local histc2=${_ble_syntax_bash_histc12:1:1} + if [[ $histc1 && $tail == "$histc1"[^"$_ble_syntax_bash_histstop"]* ]]; then + if ((ctx==_ble_ctx_QUOT)); then + local tail=${tail%%'"'*} + [[ $tail == '!' ]] && return 1 + fi + ((_ble_syntax_attr[i]=_ble_attr_HISTX)) + local rex_event + ble/syntax:bash/check-history-expansion/.initialize-event + if [[ $tail =~ $rex_event ]]; then + ((i+=${#BASH_REMATCH})) + elif [[ $tail == "$histc1"['-:0-9^$%*']* ]]; then + ((_ble_syntax_attr[i]=_ble_attr_HISTX,i++)) + else + ((_ble_syntax_attr[i+1]=_ble_attr_ERR,i+=2)) + return 0 + fi + [[ ${text:i} =~ $_ble_syntax_bash_histexpand_RexWord ]] && + ((i+=${#BASH_REMATCH})) + ble/syntax:bash/check-history-expansion/.check-modifiers + return 0 + elif ((i==0)) && [[ $histc2 && $tail == "$histc2"* ]]; then + ((_ble_syntax_attr[i]=_ble_attr_HISTX)) + local rex_quicksub + ble/syntax:bash/check-history-expansion/.initialize-quicksub + if [[ $tail =~ $rex_quicksub ]]; then + ((i+=${#BASH_REMATCH})) + ble/syntax:bash/check-history-expansion/.check-modifiers + return 0 + else + ((i+=${#tail})) + return 0 + fi + fi + return 1 +} +function ble/syntax:bash/starts-with-histchars { + [[ $_ble_syntax_bash_histc12 && $tail == ["$_ble_syntax_bash_histc12"]* ]] +} +_BLE_SYNTAX_FCTX[_ble_ctx_QUOT]=ble/syntax:bash/ctx-quot +function ble/syntax:bash/ctx-quot { + if ble/syntax:bash/check-plain-with-escape "[^${_ble_syntax_bash_chars[_ble_ctx_QUOT]}]+" 1; then + return 0 + elif [[ $tail == '"'* ]]; then + ((_ble_syntax_attr[i]=_ble_attr_QDEL, + i+=1)) + ble/syntax/parse/nest-pop + return 0 + elif ble/syntax:bash/check-quotes; then + return 0 + elif ble/syntax:bash/check-dollar; then + return 0 + elif ble/syntax:bash/starts-with-histchars; then + ble/syntax:bash/check-history-expansion || + ((_ble_syntax_attr[i]=ctx,i++)) + return 0 + fi + return 1 +} +_BLE_SYNTAX_FCTX[_ble_ctx_CASE]=ble/syntax:bash/ctx-case +function ble/syntax:bash/ctx-case { + if [[ $tail =~ ^$_ble_syntax_bash_RexIFSs ]]; then + ((_ble_syntax_attr[i]=ctx,i+=${#BASH_REMATCH})) + return 0 + elif [[ $tail == '('* ]]; then + ((_ble_syntax_attr[i++]=_ble_attr_GLOB,ctx=_ble_ctx_CPATX)) + return 0 + elif [[ $tail == 'esac'$_ble_syntax_bash_RexDelimiter* || $tail == 'esac' ]]; then + ((ctx=_ble_ctx_CMDX)) + ble/syntax:bash/ctx-command + else + ((ctx=_ble_ctx_CPATX)) + ble/syntax:bash/ctx-command-case-pattern-expect + fi +} +_BLE_SYNTAX_FCTX[_ble_ctx_PATN]=ble/syntax:bash/ctx-globpat +_BLE_SYNTAX_FEND[_ble_ctx_PATN]=ble/syntax:bash/ctx-globpat.end +function ble/syntax:bash/ctx-globpat/get-stop-chars { + chars=${_ble_syntax_bash_chars[_ble_ctx_PATN]} + local ntype; ble/syntax/parse/nest-type + if [[ $ntype == glob_ctx=* ]]; then + local gctx=${ntype#glob_ctx=} + if ((gctx==_ble_ctx_PWORD||gctx==_ble_ctx_PWORDE)); then + chars=}$chars + elif ((gctx==_ble_ctx_PWORDR)); then + chars=}/$chars + fi + fi +} +function ble/syntax:bash/ctx-globpat { + local chars; ble/syntax:bash/ctx-globpat/get-stop-chars + if ble/syntax:bash/check-plain-with-escape "[^$chars]+"; then + return 0 + elif ble/syntax:bash/check-process-subst; then + return 0 + elif [[ $tail == ['<>']* ]]; then + ((_ble_syntax_attr[i++]=ctx)) + return 0 + elif ble/syntax:bash/check-quotes; then + return 0 + elif ble/syntax:bash/check-dollar; then + return 0 + elif ble/syntax:bash/check-glob; then + return 0 + elif ble/syntax:bash/check-brace-expansion; then + return 0 + elif ble/syntax:bash/starts-with-histchars; then + ble/syntax:bash/check-history-expansion || + ((_ble_syntax_attr[i]=ctx,i++)) + return 0 + fi + return 1 +} +function ble/syntax:bash/ctx-globpat.end { + local is_end= tail=${text:i} + local ntype; ble/syntax/parse/nest-type + if [[ $ntype == glob_ctx=* ]]; then + local gctx=${ntype#glob_ctx=} + if ((gctx==_ble_ctx_PWORD||gctx==_ble_ctx_PWORDE)); then + [[ ! $tail || $tail == '}'* ]] && is_end=1 + elif ((gctx==_ble_ctx_PWORDR)); then + [[ ! $tail || $tail == ['/}']* ]] && is_end=1 + fi + fi + if [[ $is_end ]]; then + ble/syntax/parse/nest-pop + ble/syntax/parse/check-end + return 0 + fi + return 0 +} +_BLE_SYNTAX_FCTX[_ble_ctx_BRAX]=ble/syntax:bash/ctx-bracket-expression +_BLE_SYNTAX_FEND[_ble_ctx_BRAX]=ble/syntax:bash/ctx-bracket-expression.end +function ble/syntax:bash/ctx-bracket-expression { + local nctx; ble/syntax/parse/nest-ctx + if ((nctx==_ble_ctx_PATN)); then + local chars; ble/syntax:bash/ctx-globpat/get-stop-chars + elif ((nctx==_ble_ctx_PWORD||nctx==_ble_ctx_PWORDE||nctx==_ble_ctx_PWORDR)); then + local chars=${_ble_syntax_bash_chars[nctx]} + else + local chars=${_ble_syntax_bash_chars[_ble_ctx_ARGI]//'~'} + fi + chars="][${chars#']'}" + local ntype; ble/syntax/parse/nest-type + local force_attr=; [[ $ntype == glob_attr=* ]] && force_attr=${ntype#*=} + local rex + if [[ $tail == ']'* ]]; then + ((_ble_syntax_attr[i++]=${force_attr:-_ble_attr_GLOB})) + ble/syntax/parse/nest-pop + if [[ $ntype == 'a[' ]]; then + local is_assign= + if [[ $tail == ']='* ]]; then + ((_ble_syntax_attr[i++]=ctx,is_assign=1)) + elif [[ $tail == ']+'* ]]; then + ble/syntax/parse/set-lookahead 2 + [[ $tail == ']+=' ]] && ((_ble_syntax_attr[i]=ctx,i+=2,is_assign=1)) + fi + if [[ $is_assign ]]; then + ble/util/assert '[[ ${_ble_syntax_bash_command_CtxAssign[ctx]} ]]' + ((ctx=_ble_syntax_bash_command_CtxAssign[ctx])) + if local tail=${text:i}; [[ $tail == '~'* ]]; then + ble/syntax:bash/check-tilde-expansion rhs + fi + fi + fi + return 0 + elif [[ $tail == '['* ]]; then + rex='^\[@([^'$chars']+(@\]?)?)?' + rex=${rex//@/:}'|'${rex//@/'\.'}'|'${rex//@/=}'|^\[' + [[ $tail =~ $rex ]] + ((_ble_syntax_attr[i]=${force_attr:-ctx}, + i+=${#BASH_REMATCH})) + return 0 + elif ctx=${force_attr:-$ctx} ble/syntax:bash/check-plain-with-escape "[^$chars]+"; then + return 0 + elif ble/syntax:bash/check-process-subst; then + return 0 + elif ble/syntax:bash/check-quotes; then + return 0 + elif ble/syntax:bash/check-dollar; then + return 0 + elif ble/syntax:bash/check-glob; then + return 0 + elif ble/syntax:bash/check-brace-expansion; then + return 0 + elif ble/syntax:bash/check-tilde-expansion; then + return 0 + elif ble/syntax:bash/starts-with-histchars; then + ble/syntax:bash/check-history-expansion || + ((_ble_syntax_attr[i++]=${force_attr:-ctx})) + return 0 + elif ((nctx==_ble_ctx_PATN)) && [[ $tail == ['<>']* ]]; then + ((_ble_syntax_attr[i++]=${force_attr:-ctx})) + return 0 + fi + return 1 +} +function ble/syntax:bash/ctx-bracket-expression.end { + local is_end= + local tail=${text:i} + if [[ ! $tail ]]; then + is_end=1 + else + local nctx; ble/syntax/parse/nest-ctx + local external_ctx=$nctx + if ((nctx==_ble_ctx_PATN)); then + local ntype; ble/syntax/parse/nest-type + [[ $ntype == glob_ctx=* ]] && + external_ctx=${ntype#glob_ctx=} + fi + if ((external_ctx==_ble_ctx_PATN)); then + [[ $tail == ')'* ]] && is_end=1 + elif ((external_ctx==_ble_ctx_PWORD||external_ctx==_ble_ctx_PWORDE)); then + [[ $tail == '}'* ]] && is_end=1 + elif ((external_ctx==_ble_ctx_PWORDR)); then + [[ $tail == ['}/']* ]] && is_end=1 + else + if ble/syntax:bash/check-word-end/is-delimiter; then + is_end=1 + elif [[ $tail == ':'* && ${_ble_syntax_bash_command_IsAssign[ctx]} ]]; then + is_end=1 + fi + fi + fi + if [[ $is_end ]]; then + ble/syntax/parse/nest-pop + ble/syntax/parse/check-end + return "$?" + fi + return 0 +} +_BLE_SYNTAX_FCTX[_ble_ctx_PARAM]=ble/syntax:bash/ctx-param +_BLE_SYNTAX_FCTX[_ble_ctx_PWORD]=ble/syntax:bash/ctx-pword +_BLE_SYNTAX_FCTX[_ble_ctx_PWORDR]=ble/syntax:bash/ctx-pword +_BLE_SYNTAX_FCTX[_ble_ctx_PWORDE]=ble/syntax:bash/ctx-pword-error +function ble/syntax:bash/ctx-param { + if [[ $tail == '}'* ]]; then + ((_ble_syntax_attr[i]=_ble_syntax_attr[inest])) + ((i+=1)) + ble/syntax/parse/nest-pop + return 0 + fi + local rex='##?|%%?|:?[-?=+]|:|/[/#%]?' + ((_ble_bash>=40000)) && rex=$rex'|,,?|\^\^?|~~?' + if ((_ble_bash>=50100)); then + rex=$rex'|@[QEPAaUuLK]?' + elif ((_ble_bash>=40400)); then + rex=$rex'|@[QEPAa]?' + fi + rex='^('$rex')' + if [[ $tail =~ $rex ]]; then + ((_ble_syntax_attr[i]=_ble_ctx_PARAM, + i+=${#BASH_REMATCH})) + if [[ $BASH_REMATCH == '/'* ]]; then + ((ctx=_ble_ctx_PWORDR)) + elif [[ $BASH_REMATCH == : ]]; then + ((ctx=_ble_ctx_EXPR,_ble_syntax_attr[i-1]=_ble_ctx_EXPR)) + elif [[ $BASH_REMATCH == @* ]]; then + ((ctx=_ble_ctx_PWORDE)) + else + ((ctx=_ble_ctx_PWORD)) + [[ $BASH_REMATCH == [':-+=?#%']* ]] && + tail=${text:i} ble/syntax:bash/check-tilde-expansion pword + fi + return 0 + else + local i0=$i + ((ctx=_ble_ctx_PWORD)) + ble/syntax:bash/ctx-pword || return 1 + if ((i0+2<=i)); then + ((_ble_syntax_attr[i0+1])) || + ((_ble_syntax_attr[i0+1]=_ble_syntax_attr[i0])) + fi + ((_ble_syntax_attr[i0]=_ble_attr_ERR)) + return 0 + fi +} +function ble/syntax:bash/ctx-pword { + if ble/syntax:bash/check-plain-with-escape "[^${_ble_syntax_bash_chars[ctx]}]+"; then + return 0 + elif ((ctx==_ble_ctx_PWORDR)) && [[ $tail == '/'* ]]; then + ((_ble_syntax_attr[i++]=_ble_ctx_PARAM,ctx=_ble_ctx_PWORD)) + return 0 + elif [[ $tail == '}'* ]]; then + ((_ble_syntax_attr[i]=_ble_syntax_attr[inest])) + ((i+=1)) + ble/syntax/parse/nest-pop + return 0 + elif ble/syntax:bash/check-quotes; then + return 0 + elif ble/syntax:bash/check-dollar; then + return 0 + elif ble/syntax:bash/check-glob; then + return 0 + elif ble/syntax:bash/starts-with-histchars; then + ble/syntax:bash/check-history-expansion || + ((_ble_syntax_attr[i]=ctx,i++)) + return 0 + fi + return 1 +} +function ble/syntax:bash/ctx-pword-error { + local i0=$i + if ble/syntax:bash/ctx-pword; then + [[ $tail == '}'* ]] || + ((_ble_syntax_attr[i0]=_ble_attr_ERR)) + return 0 + else + return 1 + fi +} +_BLE_SYNTAX_FCTX[_ble_ctx_EXPR]=ble/syntax:bash/ctx-expr +function ble/syntax:bash/ctx-expr/.count-paren { + if [[ $char == ')' ]]; then + if [[ $ntype == '((' || $ntype == '$((' ]]; then + if [[ $tail == '))'* ]]; then + ((_ble_syntax_attr[i]=_ble_syntax_attr[inest])) + ((i+=2)) + ble/syntax/parse/nest-pop + else + ((ctx=_ble_ctx_ARGX0, + _ble_syntax_attr[i++]=_ble_syntax_attr[inest])) + fi + return 0 + elif [[ $ntype == '(' || $ntype == 'NQ(' ]]; then + ((_ble_syntax_attr[i++]=ctx)) + ble/syntax/parse/nest-pop + return 0 + fi + elif [[ $char == '(' ]]; then + local ntype2='(' + [[ $ntype == '$((' || $ntype == 'NQ(' ]] && ntype2='NQ(' + ble/syntax/parse/nest-push "$_ble_ctx_EXPR" "$ntype2" + ((_ble_syntax_attr[i++]=ctx)) + return 0 + fi + return 1 +} +function ble/syntax:bash/ctx-expr/.count-bracket { + if [[ $char == ']' ]]; then + if [[ $ntype == '[' || $ntype == '$[' ]]; then + ((_ble_syntax_attr[i]=_ble_syntax_attr[inest])) + ((i++)) + ble/syntax/parse/nest-pop + return 0 + elif [[ $ntype == [ad]'[' ]]; then + ((_ble_syntax_attr[i++]=_ble_ctx_EXPR)) + ble/syntax/parse/nest-pop + if [[ $tail == ']='* ]]; then + ((i++)) + tail=${text:i} ble/syntax:bash/check-tilde-expansion rhs + elif ((_ble_bash>=30100)) && [[ $tail == ']+'* ]]; then + ble/syntax/parse/set-lookahead 2 + if [[ $tail == ']+='* ]]; then + ((i+=2)) + tail=${text:i} ble/syntax:bash/check-tilde-expansion rhs + fi + else + if [[ $ntype == 'a[' ]]; then + if ((ctx==_ble_ctx_VRHS)); then + ((ctx=_ble_ctx_CMDI,wtype=_ble_ctx_CMDI)) + elif ((ctx==_ble_ctx_ARGVR)); then + ((ctx=_ble_ctx_ARGVI,wtype=_ble_ctx_ARGVI)) + elif ((ctx==_ble_ctx_ARGER)); then + ((ctx=_ble_ctx_ARGEI,wtype=_ble_ctx_ARGEI)) + fi + else # ntype == 'd[' + ((ctx=_ble_ctx_VALI,wtype=_ble_ctx_VALI)) + fi + fi + return 0 + elif [[ $ntype == 'v[' ]]; then + ((_ble_syntax_attr[i++]=_ble_ctx_EXPR)) + ble/syntax/parse/nest-pop + return 0 + fi + elif [[ $char == '[' ]]; then + ble/syntax/parse/nest-push "$_ble_ctx_EXPR" '[' + ((_ble_syntax_attr[i++]=ctx)) + return 0 + fi + return 1 +} +function ble/syntax:bash/ctx-expr/.count-brace { + if [[ $char == '}' ]]; then + ((_ble_syntax_attr[i]=_ble_syntax_attr[inest])) + ((i++)) + ble/syntax/parse/nest-pop + return 0 + fi + return 1 +} +function ble/syntax:bash/ctx-expr { + local rex + if rex='^[a-zA-Z_][a-zA-Z_0-9]*'; [[ $tail =~ $rex ]]; then + local rematch=$BASH_REMATCH + local ret; ble/syntax/highlight/vartype "$BASH_REMATCH" readvar:expr + ((_ble_syntax_attr[i]=ret,i+=${#rematch})) + return 0 + elif rex='^0[xX][0-9a-fA-F]*|^[0-9]+(#[0-9a-zA-Z@_]*)?'; [[ $tail =~ $rex ]]; then + ((_ble_syntax_attr[i]=_ble_attr_VAR_NUMBER,i+=${#BASH_REMATCH})) + return 0 + elif ble/syntax:bash/check-plain-with-escape "[^${_ble_syntax_bash_chars[ctx]}a-zA-Z_0-9]+" 1; then + return 0 + elif [[ $tail == ['][()}']* ]]; then + local char=${tail::1} ntype + ble/syntax/parse/nest-type + if [[ $ntype == *'(' ]]; then + ble/syntax:bash/ctx-expr/.count-paren && return 0 + elif [[ $ntype == *'[' ]]; then + ble/syntax:bash/ctx-expr/.count-bracket && return 0 + elif [[ $ntype == '${' || $ntype == '"${' ]]; then + ble/syntax:bash/ctx-expr/.count-brace && return 0 + else + ble/util/assert 'false' "unexpected ntype=$ntype for arithmetic expression" + fi + ((_ble_syntax_attr[i++]=ctx)) + return 0 + elif ble/syntax:bash/check-quotes; then + return 0 + elif ble/syntax:bash/check-dollar; then + return 0 + elif ble/syntax:bash/starts-with-histchars; then + ble/syntax:bash/check-history-expansion || + ((_ble_syntax_attr[i]=ctx,i++)) + return 0 + fi + return 1 +} +function ble/syntax:bash/check-brace-expansion { + [[ $tail == '{'* ]] || return 1 + local rex='^\{[-+0-9a-zA-Z.]*(\}?)' + [[ $tail =~ $rex ]] + local str=$BASH_REMATCH + local force_attr= inactive= + if [[ $- != *B* ]]; then + inactive=1 + elif ((ctx==_ble_ctx_CONDI||ctx==_ble_ctx_CONDQ||ctx==_ble_ctx_RDRS||ctx==_ble_ctx_VRHS)); then + inactive=1 + elif ((ctx==_ble_ctx_PATN||ctx==_ble_ctx_BRAX)); then + local ntype; ble/syntax/parse/nest-type + if [[ $ntype == glob_attr=* ]]; then + force_attr=${ntype#*=} + (((force_attr==_ble_ctx_RDRS||force_attr==_ble_ctx_VRHS||force_attr==_ble_ctx_ARGVR||force_attr==_ble_ctx_ARGER||force_attr==_ble_ctx_VALR)&&(inactive=1))) + elif ((ctx==_ble_ctx_BRAX)); then + local nctx; ble/syntax/parse/nest-ctx + (((nctx==_ble_ctx_CONDI||octx==_ble_ctx_CONDQ)&&(inactive=1))) + fi + elif ((ctx==_ble_ctx_BRACE1||ctx==_ble_ctx_BRACE2)); then + local ntype; ble/syntax/parse/nest-type + if [[ $ntype == glob_attr=* ]]; then + force_attr=${ntype#*=} + fi + fi + if [[ $inactive ]]; then + ((_ble_syntax_attr[i]=${force_attr:-ctx},i+=${#str})) + return 0 + fi + [[ ${_ble_syntax_bash_command_IsAssign[ctx]} ]] && + ctx=${_ble_syntax_bash_command_IsAssign[ctx]} + if rex='^\{(([-+]?[0-9]+)\.\.[-+]?[0-9]+|[a-zA-Z]\.\.[a-zA-Z])(\.\.[-+]?[0-9]+)?\}$'; [[ $str =~ $rex ]]; then + if [[ $force_attr ]]; then + ((_ble_syntax_attr[i]=force_attr,i+=${#str})) + else + local rematch1=${BASH_REMATCH[1]} + local rematch2=${BASH_REMATCH[2]} + local rematch3=${BASH_REMATCH[3]} + local len2=${#rematch2}; ((len2||(len2=1))) + local attr=$_ble_attr_BRACE + if ((ctx==_ble_ctx_RDRF||ctx==_ble_ctx_RDRD||ctx==_ble_ctx_RDRD2)); then + local lhs=${rematch1::len2} rhs=${rematch1:len2+2} + if [[ $rematch2 ]]; then + local lhs1=$((10#0${lhs#[-+]})); [[ $lhs == -* ]] && ((lhs1=-lhs1)) + local rhs1=$((10#0${rhs#[-+]})); [[ $rhs == -* ]] && ((rhs1=-rhs1)) + lhs=$lhs1 rhs=$rhs1 + fi + [[ $lhs != "$rhs" ]] && ((attr=_ble_attr_ERR)) + fi + ((_ble_syntax_attr[i++]=attr)) + ((_ble_syntax_attr[i]=ctx,i+=len2, + _ble_syntax_attr[i]=_ble_attr_BRACE,i+=2, + _ble_syntax_attr[i]=ctx,i+=${#rematch1}-len2-2)) + if [[ $rematch3 ]]; then + ((_ble_syntax_attr[i]=_ble_attr_BRACE,i+=2, + _ble_syntax_attr[i]=ctx,i+=${#rematch3}-2)) + fi + ((_ble_syntax_attr[i++]=attr)) + fi + return 0 + fi + local ntype= + ((ctx==_ble_ctx_RDRF||ctx==_ble_ctx_RDRD||ctx==_ble_ctx_RDRD2)) && force_attr=$ctx + [[ $force_attr ]] && ntype="glob_attr=$force_attr" + ble/syntax/parse/nest-push "$_ble_ctx_BRACE1" "$ntype" + local len=$((${#str}-1)) + ((_ble_syntax_attr[i++]=${force_attr:-_ble_attr_BRACE}, + len&&(_ble_syntax_attr[i]=${force_attr:-ctx},i+=len))) + return 0 +} +_BLE_SYNTAX_FCTX[_ble_ctx_BRACE1]=ble/syntax:bash/ctx-brace-expansion +_BLE_SYNTAX_FCTX[_ble_ctx_BRACE2]=ble/syntax:bash/ctx-brace-expansion +_BLE_SYNTAX_FEND[_ble_ctx_BRACE1]=ble/syntax:bash/ctx-brace-expansion.end +_BLE_SYNTAX_FEND[_ble_ctx_BRACE2]=ble/syntax:bash/ctx-brace-expansion.end +function ble/syntax:bash/ctx-brace-expansion { + if [[ $tail == '}'* ]] && ((ctx==_ble_ctx_BRACE2)); then + local force_attr= + local ntype; ble/syntax/parse/nest-type + [[ $ntype == glob_attr=* ]] && force_attr=$_ble_attr_ERR # ※${ntype#*=} ではなくエラー + ((_ble_syntax_attr[i++]=${force_attr:-_ble_attr_BRACE})) + ble/syntax/parse/nest-pop + return 0 + elif [[ $tail == ','* ]]; then + local force_attr= + local ntype; ble/syntax/parse/nest-type + [[ $ntype == glob_attr=* ]] && force_attr=${ntype#*=} + ((_ble_syntax_attr[i++]=${force_attr:-_ble_attr_BRACE})) + ((ctx=_ble_ctx_BRACE2)) + return 0 + fi + local chars=",${_ble_syntax_bash_chars[_ble_ctx_ARGI]//'~:'}" + ((ctx==_ble_ctx_BRACE2)) && chars="}$chars" + ble/syntax:bash/cclass/update/reorder chars + if ble/syntax:bash/check-plain-with-escape "[^$chars]+"; then + return 0 + elif ble/syntax:bash/check-process-subst; then + return 0 + elif ble/syntax:bash/check-quotes; then + return 0 + elif ble/syntax:bash/check-dollar; then + return 0 + elif ble/syntax:bash/check-glob; then + return 0 + elif ble/syntax:bash/check-brace-expansion; then + return 0 + elif ble/syntax:bash/starts-with-histchars; then + ble/syntax:bash/check-history-expansion || + ((_ble_syntax_attr[i++]=ctx)) + return 0 + fi + return 1 +} +function ble/syntax:bash/ctx-brace-expansion.end { + if ((i==${#text})) || ble/syntax:bash/check-word-end/is-delimiter; then + ble/syntax/parse/nest-pop + ble/syntax/parse/check-end + return "$?" + fi + return 0 +} +function ble/syntax:bash/check-tilde-expansion { + [[ $tail == ['~:']* ]] || return 1 + local rhs_enabled= + { ((ctx==_ble_ctx_VRHS||ctx==_ble_ctx_ARGVR||ctx==_ble_ctx_VALR||ctx==_ble_ctx_ARGER)) || + ! ble/base/is-POSIXLY_CORRECT; } && rhs_enabled=1 + local tilde_enabled=$((i==wbegin||ctx==_ble_ctx_PWORD)) + [[ $1 == rhs && $rhs_enabled ]] && tilde_enabled=1 # = の直後 + if [[ $tail == ':'* ]]; then + _ble_syntax_attr[i++]=$ctx + if [[ $rhs_enabled ]]; then + if ! ((tilde_enabled=_ble_syntax_bash_command_IsAssign[ctx])); then + if ((ctx==_ble_ctx_BRAX)); then + local nctx; ble/syntax/parse/nest-ctx + ((tilde_enabled=_ble_syntax_bash_command_IsAssign[nctx])) + fi + fi + fi + local tail=${text:i} + [[ $tail == '~'* ]] || return 0 + fi + if ((tilde_enabled)); then + local chars="${_ble_syntax_bash_chars[_ble_ctx_ARGI]}/:" + ((ctx==_ble_ctx_PWORD)) && chars=${chars/'{'/'{}'} + ble/syntax:bash/cclass/update/reorder chars + local delimiters="$_ble_term_IFS;|&)<>" + local rex='^(~\+|~[^'$chars']*)([^'$delimiters'/:]?)'; [[ $tail =~ $rex ]] + local str=${BASH_REMATCH[1]} + local path attr=$ctx + builtin eval "path=$str" + if [[ ! ${BASH_REMATCH[2]} && $path != "$str" ]]; then + ((attr=_ble_attr_TILDE)) + if ((ctx==_ble_ctx_BRAX)); then + ble/util/assert 'ble/util/unlocal tail; [[ $tail == ":~"* ]]' + ble/syntax/parse/nest-pop + fi + else + if [[ $str == '~+' ]]; then + ble/syntax/parse/set-lookahead 3 + str='~' + fi + fi + ((_ble_syntax_attr[i]=attr,i+=${#str})) + else + ((_ble_syntax_attr[i]=ctx,i++)) # skip tilde + local chars=${_ble_syntax_bash_chars[_ble_ctx_ARGI]} + ble/syntax:bash/check-plain-with-escape "[^$chars]+" # 追加(失敗してもOK) + fi + return 0 +} +_ble_syntax_bash_command_CtxAssign[_ble_ctx_CMDI]=$_ble_ctx_VRHS +_ble_syntax_bash_command_CtxAssign[_ble_ctx_COARGI]=$_ble_ctx_VRHS +_ble_syntax_bash_command_CtxAssign[_ble_ctx_ARGVI]=$_ble_ctx_ARGVR +_ble_syntax_bash_command_CtxAssign[_ble_ctx_ARGEI]=$_ble_ctx_ARGER +_ble_syntax_bash_command_CtxAssign[_ble_ctx_ARGI]=$_ble_ctx_ARGQ +_ble_syntax_bash_command_CtxAssign[_ble_ctx_FARGI3]=$_ble_ctx_FARGQ3 +_ble_syntax_bash_command_CtxAssign[_ble_ctx_CARGI1]=$_ble_ctx_CARGQ1 +_ble_syntax_bash_command_CtxAssign[_ble_ctx_CPATI]=$_ble_ctx_CPATQ +_ble_syntax_bash_command_CtxAssign[_ble_ctx_VALI]=$_ble_ctx_VALQ +_ble_syntax_bash_command_CtxAssign[_ble_ctx_CONDI]=$_ble_ctx_CONDQ +_ble_syntax_bash_command_IsAssign[_ble_ctx_VRHS]=$_ble_ctx_CMDI +_ble_syntax_bash_command_IsAssign[_ble_ctx_ARGVR]=$_ble_ctx_ARGVI +_ble_syntax_bash_command_IsAssign[_ble_ctx_ARGER]=$_ble_ctx_ARGEI +_ble_syntax_bash_command_IsAssign[_ble_ctx_ARGQ]=$_ble_ctx_ARGI +_ble_syntax_bash_command_IsAssign[_ble_ctx_FARGQ3]=$_ble_ctx_FARGI3 +_ble_syntax_bash_command_IsAssign[_ble_ctx_CARGQ1]=$_ble_ctx_CARGI1 +_ble_syntax_bash_command_IsAssign[_ble_ctx_CPATQ]=$_ble_ctx_CPATI +_ble_syntax_bash_command_IsAssign[_ble_ctx_VALR]=$_ble_ctx_VALI +_ble_syntax_bash_command_IsAssign[_ble_ctx_VALQ]=$_ble_ctx_VALI +_ble_syntax_bash_command_IsAssign[_ble_ctx_CONDQ]=$_ble_ctx_CONDI +function ble/syntax:bash/check-variable-assignment { + ((wbegin==i)) || return 1 + if ((ctx==_ble_ctx_VALI)) && [[ $tail == '['* ]]; then + ((ctx=_ble_ctx_VALR)) + ble/syntax/parse/nest-push "$_ble_ctx_EXPR" 'd[' + ((_ble_syntax_attr[i++]=ctx)) + return 0 + fi + [[ ${_ble_syntax_bash_command_CtxAssign[ctx]} ]] || return 1 + local suffix='[=[]' + ((_ble_bash>=30100)) && suffix=$suffix'|\+=?' + local rex_assign="^([a-zA-Z_][a-zA-Z_0-9]*)($suffix)" + [[ $tail =~ $rex_assign ]] || return 1 + local rematch=$BASH_REMATCH + local rematch1=${BASH_REMATCH[1]} # for bash-3.1 ${#arr[n]} bug + local rematch2=${BASH_REMATCH[2]} # for bash-3.1 ${#arr[n]} bug + if [[ $rematch2 == '+' ]]; then + ble/syntax/parse/set-lookahead $((${#rematch}+1)) + return 1 + fi + local variable_assign= + if ((ctx==_ble_ctx_CMDI||ctx==_ble_ctx_ARGVI||ctx==_ble_ctx_ARGEI&&${#rematch2})); then + local ret; ble/syntax/highlight/vartype "$rematch1" + ((wtype=_ble_attr_VAR, + _ble_syntax_attr[i]=ret, + i+=${#rematch}, + ${#rematch2}&&(_ble_syntax_attr[i-${#rematch2}]=_ble_ctx_EXPR), + variable_assign=1, + ctx=_ble_syntax_bash_command_CtxAssign[ctx])) + else + ((_ble_syntax_attr[i]=ctx, + i+=${#rematch})) + fi + if [[ $rematch2 == '[' ]]; then + if [[ $variable_assign ]]; then + i=$((i-1)) ble/syntax/parse/nest-push "$_ble_ctx_EXPR" 'a[' + else + ((i--)) + tail=${text:i} ble/syntax:bash/check-glob assign + fi + elif [[ $rematch2 == *'=' ]]; then + if [[ $variable_assign && ${text:i} == '('* ]]; then + ble/syntax:bash/ctx-values/enter + ((_ble_syntax_attr[i++]=_ble_attr_DEL)) + else + [[ $variable_assign ]] || ((ctx=_ble_syntax_bash_command_CtxAssign[ctx])) + if local tail=${text:i}; [[ $tail == '~'* ]]; then + ble/syntax:bash/check-tilde-expansion rhs + fi + fi + fi + return 0 +} +_BLE_SYNTAX_FCTX[_ble_ctx_ARGX]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_ARGX0]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_CMDX]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_CMDX1]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_CMDXT]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_CMDXC]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_CMDXE]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_CMDXD]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_CMDXD0]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_CMDXV]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_ARGI]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_ARGQ]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_CMDI]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_VRHS]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_ARGVR]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_ARGER]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FEND[_ble_ctx_CMDI]=ble/syntax:bash/ctx-command/check-word-end +_BLE_SYNTAX_FEND[_ble_ctx_ARGI]=ble/syntax:bash/ctx-command/check-word-end +_BLE_SYNTAX_FEND[_ble_ctx_ARGQ]=ble/syntax:bash/ctx-command/check-word-end +_BLE_SYNTAX_FEND[_ble_ctx_VRHS]=ble/syntax:bash/ctx-command/check-word-end +_BLE_SYNTAX_FEND[_ble_ctx_ARGVR]=ble/syntax:bash/ctx-command/check-word-end +_BLE_SYNTAX_FEND[_ble_ctx_ARGER]=ble/syntax:bash/ctx-command/check-word-end +_BLE_SYNTAX_FCTX[_ble_ctx_ARGVX]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_ARGVI]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FEND[_ble_ctx_ARGVI]=ble/syntax:bash/ctx-command/check-word-end +_BLE_SYNTAX_FCTX[_ble_ctx_ARGEX]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_ARGEI]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FEND[_ble_ctx_ARGEI]=ble/syntax:bash/ctx-command/check-word-end +_BLE_SYNTAX_FCTX[_ble_ctx_SARGX1]=ble/syntax:bash/ctx-command-compound-expect +_BLE_SYNTAX_FCTX[_ble_ctx_FARGX1]=ble/syntax:bash/ctx-command-compound-expect +_BLE_SYNTAX_FCTX[_ble_ctx_FARGX2]=ble/syntax:bash/ctx-command-compound-expect +_BLE_SYNTAX_FCTX[_ble_ctx_FARGX3]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_FARGI1]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_FARGI2]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_FARGI3]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_FARGQ3]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FEND[_ble_ctx_FARGI1]=ble/syntax:bash/ctx-command/check-word-end +_BLE_SYNTAX_FEND[_ble_ctx_FARGI2]=ble/syntax:bash/ctx-command/check-word-end +_BLE_SYNTAX_FEND[_ble_ctx_FARGI3]=ble/syntax:bash/ctx-command/check-word-end +_BLE_SYNTAX_FEND[_ble_ctx_FARGQ3]=ble/syntax:bash/ctx-command/check-word-end +_BLE_SYNTAX_FCTX[_ble_ctx_CARGX1]=ble/syntax:bash/ctx-command-compound-expect +_BLE_SYNTAX_FCTX[_ble_ctx_CARGX2]=ble/syntax:bash/ctx-command-compound-expect +_BLE_SYNTAX_FCTX[_ble_ctx_CPATX]=ble/syntax:bash/ctx-command-case-pattern-expect +_BLE_SYNTAX_FCTX[_ble_ctx_CPATX0]=ble/syntax:bash/ctx-command-case-pattern-expect +_BLE_SYNTAX_FCTX[_ble_ctx_CARGI1]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_CARGQ1]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_CARGI2]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_CPATI]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_CPATQ]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FEND[_ble_ctx_CARGI1]=ble/syntax:bash/ctx-command/check-word-end +_BLE_SYNTAX_FEND[_ble_ctx_CARGQ1]=ble/syntax:bash/ctx-command/check-word-end +_BLE_SYNTAX_FEND[_ble_ctx_CARGI2]=ble/syntax:bash/ctx-command/check-word-end +_BLE_SYNTAX_FEND[_ble_ctx_CPATI]=ble/syntax:bash/ctx-command/check-word-end +_BLE_SYNTAX_FEND[_ble_ctx_CPATQ]=ble/syntax:bash/ctx-command/check-word-end +_BLE_SYNTAX_FCTX[_ble_ctx_TARGX1]=ble/syntax:bash/ctx-command-time-expect +_BLE_SYNTAX_FCTX[_ble_ctx_TARGX2]=ble/syntax:bash/ctx-command-time-expect +_BLE_SYNTAX_FCTX[_ble_ctx_TARGI1]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[_ble_ctx_TARGI2]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FEND[_ble_ctx_TARGI1]=ble/syntax:bash/ctx-command/check-word-end +_BLE_SYNTAX_FEND[_ble_ctx_TARGI2]=ble/syntax:bash/ctx-command/check-word-end +_BLE_SYNTAX_FCTX[_ble_ctx_COARGX]=ble/syntax:bash/ctx-command-compound-expect +_BLE_SYNTAX_FEND[_ble_ctx_COARGI]=ble/syntax:bash/ctx-coproc/check-word-end +function ble/syntax:bash/starts-with-delimiter-or-redirect { + local delimiters=$_ble_syntax_bash_RexDelimiter + local redirect=$_ble_syntax_bash_RexRedirect + [[ ( $tail =~ ^$delimiters || $wbegin -lt 0 && $tail =~ ^$redirect || $wbegin -lt 0 && $tail == $'\\\n'* ) && $tail != ['<>']'('* ]] +} +function ble/syntax:bash/starts-with-delimiter { + [[ $tail == ["$_ble_term_IFS;|&<>()"]* && $tail != ['<>']'('* ]] +} +function ble/syntax:bash/check-word-end/is-delimiter { + local tail=${text:i} + if [[ $tail == [!"$_ble_term_IFS;|&<>()"]* ]]; then + return 1 + elif [[ $tail == ['<>']* ]]; then + ble/syntax/parse/set-lookahead 2 + [[ $tail == ['<>']'('* ]] && return 1 + fi + return 0 +} +function ble/syntax:bash/check-here-document-from { + local spaces=$1 + [[ $nparam && $spaces == *$'\n'* ]] || return 1 + local rex="$_ble_term_FS@([RI][QH][^$_ble_term_FS]*)(.*$)" && [[ $nparam =~ $rex ]] || return 1 + local rematch1=${BASH_REMATCH[1]} + local rematch2=${BASH_REMATCH[2]} + local padding=${spaces%%$'\n'*} + ((_ble_syntax_attr[i]=ctx,i+=${#padding})) + nparam=${nparam::${#nparam}-${#BASH_REMATCH}}${nparam:${#nparam}-${#rematch2}} + ble/syntax/parse/nest-push "$_ble_ctx_HERE0" + ((i++)) + nparam=$rematch1 + return 0 +} +function ble/syntax:bash/ctx-coproc/.is-next-compound { + local p=$i ahead=1 tail=${text:i} + if local rex=$'^[ \t]+'; [[ $tail =~ $rex ]]; then + ((p+=${#BASH_REMATCH})) + ahead=1 tail=${text:p} + fi + local is_compound= + if [[ $tail == '('* ]]; then + is_compound=1 + elif rex='^[a-z]+|^\[\[?|^[{}!]'; [[ $tail =~ $rex ]]; then + local rematch=$BASH_REMATCH + ((p+=${#rematch})) + [[ $rematch == ['{}!'] || $rematch == '[[' ]]; ahead=$? + rex='^(\[\[|for|select|case|if|while|until|fi|done|esac|then|elif|else|do|[{}!]|coproc|function)$' + if [[ $rematch =~ $rex ]]; then + if rex='^[;|&()'$_ble_term_IFS']|^$|^[<>]\(?' ahead=1; [[ ${text:p} =~ $rex ]]; then + local rematch=$BASH_REMATCH + ((p+=${#rematch})) + [[ $rematch && $rematch != ['<>'] ]]; ahead=$? + [[ $rematch != ['<>']'(' ]] && is_compound=1 + fi + fi + fi + ble/syntax/parse/set-lookahead $((p+ahead-i)) + [[ $is_compound ]] +} +function ble/syntax:bash/ctx-coproc/check-word-end { + ble/util/assert '((ctx==_ble_ctx_COARGI))' + ((wbegin<0)) && return 1 + ble/syntax:bash/check-word-end/is-delimiter || return 1 + local wbeg=$wbegin wlen=$((i-wbegin)) wend=$i + local word=${text:wbegin:wlen} + local wt=$wtype + if local rex='^[_a-zA-Z0-9]+$'; [[ $word =~ $rex ]]; then + if ble/syntax:bash/ctx-coproc/.is-next-compound; then + ((_ble_syntax_attr[wbegin]=_ble_attr_VAR)) + ((ctx=_ble_ctx_CMDXC,type=_ble_ctx_ARGVI)) + ble/syntax/parse/word-pop + return 0 + fi + fi + ((ctx=_ble_ctx_CMDI,wtype=_ble_ctx_CMDX)) + ble/syntax:bash/ctx-command/check-word-end +} +_ble_syntax_bash_command_EndCtx=() +_ble_syntax_bash_command_EndCtx[_ble_ctx_ARGI]=$_ble_ctx_ARGX +_ble_syntax_bash_command_EndCtx[_ble_ctx_ARGQ]=$_ble_ctx_ARGX +_ble_syntax_bash_command_EndCtx[_ble_ctx_ARGVI]=$_ble_ctx_ARGVX +_ble_syntax_bash_command_EndCtx[_ble_ctx_ARGVR]=$_ble_ctx_ARGVX +_ble_syntax_bash_command_EndCtx[_ble_ctx_ARGEI]=$_ble_ctx_ARGEX +_ble_syntax_bash_command_EndCtx[_ble_ctx_ARGER]=$_ble_ctx_ARGEX +_ble_syntax_bash_command_EndCtx[_ble_ctx_VRHS]=$_ble_ctx_CMDXV +_ble_syntax_bash_command_EndCtx[_ble_ctx_FARGI1]=$_ble_ctx_FARGX2 +_ble_syntax_bash_command_EndCtx[_ble_ctx_FARGI2]=$_ble_ctx_FARGX3 +_ble_syntax_bash_command_EndCtx[_ble_ctx_FARGI3]=$_ble_ctx_FARGX3 +_ble_syntax_bash_command_EndCtx[_ble_ctx_FARGQ3]=$_ble_ctx_FARGX3 +_ble_syntax_bash_command_EndCtx[_ble_ctx_CARGI1]=$_ble_ctx_CARGX2 +_ble_syntax_bash_command_EndCtx[_ble_ctx_CARGQ1]=$_ble_ctx_CARGX2 +_ble_syntax_bash_command_EndCtx[_ble_ctx_CARGI2]=$_ble_ctx_CASE +_ble_syntax_bash_command_EndCtx[_ble_ctx_CPATI]=$_ble_ctx_CPATX0 +_ble_syntax_bash_command_EndCtx[_ble_ctx_CPATQ]=$_ble_ctx_CPATX0 +_ble_syntax_bash_command_EndCtx[_ble_ctx_TARGI1]=$((_ble_bash>=40200?_ble_ctx_TARGX2:_ble_ctx_CMDXT)) #1 +_ble_syntax_bash_command_EndCtx[_ble_ctx_TARGI2]=$_ble_ctx_CMDXT +_ble_syntax_bash_command_EndWtype[_ble_ctx_ARGX]=$_ble_ctx_ARGI +_ble_syntax_bash_command_EndWtype[_ble_ctx_ARGX0]=$_ble_ctx_ARGI +_ble_syntax_bash_command_EndWtype[_ble_ctx_ARGVX]=$_ble_ctx_ARGVI +_ble_syntax_bash_command_EndWtype[_ble_ctx_ARGEX]=$_ble_ctx_ARGEI +_ble_syntax_bash_command_EndWtype[_ble_ctx_CMDX]=$_ble_ctx_CMDI +_ble_syntax_bash_command_EndWtype[_ble_ctx_CMDX1]=$_ble_ctx_CMDI +_ble_syntax_bash_command_EndWtype[_ble_ctx_CMDXT]=$_ble_ctx_CMDI +_ble_syntax_bash_command_EndWtype[_ble_ctx_CMDXC]=$_ble_ctx_CMDI +_ble_syntax_bash_command_EndWtype[_ble_ctx_CMDXE]=$_ble_ctx_CMDI +_ble_syntax_bash_command_EndWtype[_ble_ctx_CMDXD]=$_ble_ctx_CMDI +_ble_syntax_bash_command_EndWtype[_ble_ctx_CMDXD0]=$_ble_ctx_CMDI +_ble_syntax_bash_command_EndWtype[_ble_ctx_CMDXV]=$_ble_ctx_CMDI +_ble_syntax_bash_command_EndWtype[_ble_ctx_FARGX1]=$_ble_ctx_FARGI1 # 変数名 +_ble_syntax_bash_command_EndWtype[_ble_ctx_SARGX1]=$_ble_ctx_ARGI +_ble_syntax_bash_command_EndWtype[_ble_ctx_FARGX2]=$_ble_ctx_FARGI2 # in +_ble_syntax_bash_command_EndWtype[_ble_ctx_FARGX3]=$_ble_ctx_ARGI # in +_ble_syntax_bash_command_EndWtype[_ble_ctx_CARGX1]=$_ble_ctx_ARGI +_ble_syntax_bash_command_EndWtype[_ble_ctx_CARGX2]=$_ble_ctx_CARGI2 # in +_ble_syntax_bash_command_EndWtype[_ble_ctx_CPATX]=$_ble_ctx_CPATI +_ble_syntax_bash_command_EndWtype[_ble_ctx_CPATX0]=$_ble_ctx_CPATI +_ble_syntax_bash_command_EndWtype[_ble_ctx_TARGX1]=$_ble_ctx_ARGI # -p +_ble_syntax_bash_command_EndWtype[_ble_ctx_TARGX2]=$_ble_ctx_ARGI # -- +_ble_syntax_bash_command_Expect=() +_ble_syntax_bash_command_Expect[_ble_ctx_CMDXC]='^(\(|\{|\(\(|\[\[|for|select|case|if|while|until)$' +_ble_syntax_bash_command_Expect[_ble_ctx_CMDXE]='^(\}|fi|done|esac|then|elif|else|do)$' +_ble_syntax_bash_command_Expect[_ble_ctx_CMDXD]='^(\{|do)$' +_ble_syntax_bash_command_Expect[_ble_ctx_CMDXD0]='^(\{|do)$' +function ble/syntax:bash/ctx-command/check-word-end { + ((wbegin<0)) && return 1 + ble/syntax:bash/check-word-end/is-delimiter || return 1 + local wbeg=$wbegin wlen=$((i-wbegin)) wend=$i + local word=${text:wbegin:wlen} + local wt=$wtype + [[ ${_ble_syntax_bash_command_EndWtype[wt]} ]] && + wtype=${_ble_syntax_bash_command_EndWtype[wt]} + local rex_expect_command=${_ble_syntax_bash_command_Expect[wt]} + if [[ $rex_expect_command ]]; then + [[ $word =~ $rex_expect_command ]] || ((wtype=_ble_attr_ERR)) + fi + if ((wt==_ble_ctx_CMDX1)); then + local rex='^(then|elif|else|do|\}|done|fi|esac)$' + [[ $word =~ $rex ]] && ((wtype=_ble_attr_ERR)) + fi + ble/syntax/parse/word-pop + if ((ctx==_ble_ctx_CMDI)); then + local ret + ble/alias#expand "$word"; local word_expanded=$ret + if ((wt!=_ble_ctx_CMDXV)); then # Note: 変数代入の直後はキーワードは処理しない + local processed= + case "$word_expanded" in + ('[[') + ble/syntax/parse/touch-updated-attr "$wbeg" + ((_ble_syntax_attr[wbeg]=_ble_attr_DEL, + ctx=_ble_ctx_ARGX0)) + ble/syntax/parse/word-cancel # 単語 "[[" (とその内部のノード全て) を削除 + if [[ $word == '[[' ]]; then + _ble_syntax_attr[wbeg+1]= # 角括弧式として着色されているのを消去 + fi + i=$wbeg ble/syntax/parse/nest-push "$_ble_ctx_CONDX" + i=$wbeg ble/syntax/parse/word-push "$_ble_ctx_CMDI" "$wbeg" + ble/syntax/parse/word-pop + return 0 ;; + ('time') ((ctx=_ble_ctx_TARGX1)); processed=keyword ;; + ('!') ((ctx=_ble_ctx_CMDXT)) ; processed=keyword ;; + ('if'|'while'|'until') ((ctx=_ble_ctx_CMDX1)) ; processed=begin ;; + ('for') ((ctx=_ble_ctx_FARGX1)); processed=begin ;; + ('select') ((ctx=_ble_ctx_SARGX1)); processed=begin ;; + ('case') ((ctx=_ble_ctx_CARGX1)); processed=begin ;; + ('{') + ((ctx=_ble_ctx_CMDX1)) + if ((wt==_ble_ctx_CMDXD||wt==_ble_ctx_CMDXD0)); then + processed=middle # "for ...; {" などの時 + else + processed=begin + fi ;; + ('then'|'elif'|'else'|'do') ((ctx=_ble_ctx_CMDX1)) ; processed=middle ;; + ('}'|'done'|'fi'|'esac') ((ctx=_ble_ctx_CMDXE)) ; processed=end ;; + ('coproc') + if ((_ble_bash>=40000)); then + if ble/syntax:bash/ctx-coproc/.is-next-compound; then + ((ctx=_ble_ctx_CMDXC)) + else + ((ctx=_ble_ctx_COARGX)) + fi + processed=keyword + fi ;; + ('function') + ((ctx=_ble_ctx_ARGX)) + local isfuncsymx=$'\t\n'' "$&'\''();<>\`|' rex_space=$'[ \t]' rex + if rex="^$rex_space+" && [[ ${text:i} =~ $rex ]]; then + ((_ble_syntax_attr[i]=_ble_ctx_ARGX,i+=${#BASH_REMATCH},ctx=_ble_ctx_ARGX)) + if rex="^([^#$isfuncsymx][^$isfuncsymx]*)($rex_space*)(\(\(|\($rex_space*\)?)?" && [[ ${text:i} =~ $rex ]]; then + local rematch1=${BASH_REMATCH[1]} + local rematch2=${BASH_REMATCH[2]} + local rematch3=${BASH_REMATCH[3]} + ((_ble_syntax_attr[i]=_ble_attr_FUNCDEF,i+=${#rematch1}, + ${#rematch2}&&(_ble_syntax_attr[i]=_ble_ctx_CMDX1,i+=${#rematch2}))) + if [[ $rematch3 == '('*')' ]]; then + ((_ble_syntax_attr[i]=_ble_attr_DEL,i+=${#rematch3},ctx=_ble_ctx_CMDXC)) + elif ((_ble_bash>=40200)) && [[ $rematch3 == '((' ]]; then + ble/syntax/parse/set-lookahead 2 + ((ctx=_ble_ctx_CMDXC)) + elif [[ $rematch3 == '('* ]]; then + ((_ble_syntax_attr[i]=_ble_attr_ERR,ctx=_ble_ctx_ARGX0)) + ble/syntax/parse/nest-push "$_ble_ctx_CMDX1" '(' + ((${#rematch3}>=2&&(_ble_syntax_attr[i+1]=_ble_ctx_CMDX1),i+=${#rematch3})) + else + ((ctx=_ble_ctx_CMDXC)) + fi + processed=keyword + fi + fi + [[ $processed ]] || ((_ble_syntax_attr[i-1]=_ble_attr_ERR)) ;; + esac + if [[ $processed ]]; then + local attr= + case $processed in + (keyword) attr=$_ble_attr_KEYWORD ;; + (begin) attr=$_ble_attr_KEYWORD_BEGIN ;; + (end) attr=$_ble_attr_KEYWORD_END ;; + (middle) attr=$_ble_attr_KEYWORD_MID ;; + esac + if [[ $attr ]]; then + ble/syntax/parse/touch-updated-attr "$wbeg" + ((_ble_syntax_attr[wbeg]=attr)) + fi + return 0 + fi + fi + ((ctx=_ble_ctx_ARGX)) + if local rex='^([ ]*)(\([ ]*\)?)?'; [[ ${text:i} =~ $rex && $BASH_REMATCH ]]; then + local rematch1=${BASH_REMATCH[1]} + local rematch2=${BASH_REMATCH[2]} + if [[ $rematch2 == '('*')' ]]; then + _ble_syntax_tree[i-1]="$_ble_attr_FUNCDEF ${_ble_syntax_tree[i-1]#* }" + ((_ble_syntax_attr[i]=_ble_ctx_CMDX1,i+=${#rematch1}, + _ble_syntax_attr[i]=_ble_attr_DEL,i+=${#rematch2}, + ctx=_ble_ctx_CMDXC)) + elif [[ $rematch2 == '('* ]]; then + ((_ble_syntax_attr[i]=_ble_ctx_ARGX0,i+=${#rematch1}, + _ble_syntax_attr[i]=_ble_attr_ERR, + ctx=_ble_ctx_ARGX0)) + ble/syntax/parse/nest-push "$_ble_ctx_PATN" + ((${#rematch2}>=2&&(_ble_syntax_attr[i+1]=_ble_ctx_CMDXC), + i+=${#rematch2})) + else + ((_ble_syntax_attr[i]=_ble_ctx_ARGX,i+=${#rematch1})) + fi + fi + case $word_expanded in + ('declare'|'readonly'|'typeset'|'local'|'export'|'alias') + ((ctx=_ble_ctx_ARGVX)) ;; + ('eval') + ((ctx=_ble_ctx_ARGEX)) ;; + esac + return 0 + fi + if ((ctx==_ble_ctx_FARGI2)); then + if [[ $word == do ]]; then + ((ctx=_ble_ctx_CMDX1)) + return 0 + fi + fi + if ((ctx==_ble_ctx_FARGI2||ctx==_ble_ctx_CARGI2)); then + if [[ $word != in ]]; then + ble/syntax/parse/touch-updated-attr "$wbeg" + ((_ble_syntax_attr[wbeg]=_ble_attr_ERR)) + fi + fi + if ((_ble_syntax_bash_command_EndCtx[ctx])); then + ((ctx=_ble_syntax_bash_command_EndCtx[ctx])) + fi + return 0 +} +_ble_syntax_bash_command_Opt=() +_ble_syntax_bash_command_Opt[_ble_ctx_ARGX]=1 +_ble_syntax_bash_command_Opt[_ble_ctx_ARGX0]=1 +_ble_syntax_bash_command_Opt[_ble_ctx_ARGVX]=1 +_ble_syntax_bash_command_Opt[_ble_ctx_ARGEX]=1 +_ble_syntax_bash_command_Opt[_ble_ctx_CMDXV]=1 +_ble_syntax_bash_command_Opt[_ble_ctx_CMDXE]=1 +_ble_syntax_bash_command_Opt[_ble_ctx_CMDXD0]=1 +_ble_syntax_bash_is_command_form_for= +function ble/syntax:bash/ctx-command/.check-delimiter-or-redirect { + if [[ $tail =~ ^$_ble_syntax_bash_RexIFSs || $wbegin -lt 0 && $tail == $'\\\n'* ]]; then + local spaces=$BASH_REMATCH + if [[ $tail == $'\\\n'* ]]; then + spaces=$'\\\n' + elif [[ $spaces == *$'\n'* ]]; then + ble/syntax:bash/check-here-document-from "$spaces" && return 0 + if ((ctx==_ble_ctx_ARGX||ctx==_ble_ctx_ARGX0||ctx==_ble_ctx_ARGVX||ctx==_ble_ctx_ARGEX||ctx==_ble_ctx_CMDXV||ctx==_ble_ctx_CMDXT||ctx==_ble_ctx_CMDXE)); then + ((ctx=_ble_ctx_CMDX)) + elif ((ctx==_ble_ctx_FARGX2||ctx==_ble_ctx_FARGX3||ctx==_ble_ctx_CMDXD0)); then + ((ctx=_ble_ctx_CMDXD)) + fi + fi + ((_ble_syntax_attr[i]=ctx,i+=${#spaces})) + return 0 + elif [[ $tail =~ ^$_ble_syntax_bash_RexRedirect ]]; then + local len=${#BASH_REMATCH} + local rematch1=${BASH_REMATCH[1]} + local rematch3=${BASH_REMATCH[3]} + ((_ble_syntax_attr[i]=_ble_attr_DEL, + ${#rematch1}<len&&(_ble_syntax_attr[i+${#rematch1}]=_ble_ctx_ARGX))) + if ((ctx==_ble_ctx_CMDX||ctx==_ble_ctx_CMDX1||ctx==_ble_ctx_CMDXT)); then + ((ctx=_ble_ctx_CMDXV)) + elif ((ctx==_ble_ctx_CMDXC||ctx==_ble_ctx_CMDXD||ctx==_ble_ctx_CMDXD0)); then + ((ctx=_ble_ctx_CMDXV, + _ble_syntax_attr[i]=_ble_attr_ERR)) + elif ((ctx==_ble_ctx_CMDXE)); then + ((ctx=_ble_ctx_ARGX0)) + elif ((ctx==_ble_ctx_FARGX3)); then + ((_ble_syntax_attr[i]=_ble_attr_ERR)) + fi + if [[ ${text:i+len} != [!$'\n|&()']* ]]; then + ((_ble_syntax_attr[i+len-1]=_ble_attr_ERR)) + else + if [[ $rematch3 == '>&' ]]; then + ble/syntax/parse/nest-push "$_ble_ctx_RDRD2" "$rematch3" + elif [[ $rematch1 == *'&' ]]; then + ble/syntax/parse/nest-push "$_ble_ctx_RDRD" "$rematch3" + elif [[ $rematch1 == *'<<<' ]]; then + ble/syntax/parse/nest-push "$_ble_ctx_RDRS" "$rematch3" + elif [[ $rematch1 == *\<\< ]]; then + ble/syntax/parse/nest-push "$_ble_ctx_RDRH" "$rematch3" + elif [[ $rematch1 == *\<\<- ]]; then + ble/syntax/parse/nest-push "$_ble_ctx_RDRI" "$rematch3" + else + ble/syntax/parse/nest-push "$_ble_ctx_RDRF" "$rematch3" + fi + fi + ((i+=len)) + return 0 + elif local rex='^(&&|\|[|&]?)|^;(;&?|&)|^[;&]' + ((_ble_bash<40000)) && rex='^(&&|\|\|?)|^;(;)|^[;&]' + [[ $tail =~ $rex ]] + then + if [[ $BASH_REMATCH == ';' ]]; then + if ((ctx==_ble_ctx_FARGX2||ctx==_ble_ctx_FARGX3||ctx==_ble_ctx_CMDXD0)); then + ((_ble_syntax_attr[i++]=_ble_attr_DEL,ctx=_ble_ctx_CMDXD)) + return 0 + elif ((ctx==_ble_ctx_CMDXT)); then + ((_ble_syntax_attr[i++]=_ble_attr_DEL,ctx=_ble_bash>=40400?_ble_ctx_CMDX:_ble_ctx_CMDXE)) + return 0 + fi + fi + local rematch1=${BASH_REMATCH[1]} rematch2=${BASH_REMATCH[2]} + ((_ble_syntax_attr[i]=_ble_attr_DEL, + (_ble_syntax_bash_command_Opt[ctx]||ctx==_ble_ctx_CMDX&&${#rematch2})|| + (_ble_syntax_attr[i]=_ble_attr_ERR))) + ((ctx=${#rematch1}?_ble_ctx_CMDX1:( + ${#rematch2}?_ble_ctx_CASE: + _ble_ctx_CMDX))) + ((i+=${#BASH_REMATCH})) + return 0 + elif local rex='^\(\(?' && [[ $tail =~ $rex ]]; then + local m=${BASH_REMATCH[0]} + if ((ctx==_ble_ctx_CMDX||ctx==_ble_ctx_CMDX1||ctx==_ble_ctx_CMDXT||ctx==_ble_ctx_CMDXC)); then + ((_ble_syntax_attr[i]=_ble_attr_DEL)) + ((ctx=${#m}==1?_ble_ctx_CMDXE:_ble_ctx_ARGX0)) + [[ $_ble_syntax_bash_is_command_form_for && $tail == '(('* ]] && ((ctx=_ble_ctx_CMDXD0)) + ble/syntax/parse/nest-push $((${#m}==1?_ble_ctx_CMDX1:_ble_ctx_EXPR)) "$m" + ((i+=${#m})) + else + ble/syntax/parse/nest-push "$_ble_ctx_PATN" + ((_ble_syntax_attr[i++]=_ble_attr_ERR)) + fi + return 0 + elif [[ $tail == ')'* ]]; then + local ntype + ble/syntax/parse/nest-type + local attr= + if [[ $ntype == '(' || $ntype == '$(' || $ntype == '((' || $ntype == '$((' ]]; then + ((attr=_ble_syntax_attr[inest])) + fi + if [[ $attr ]]; then + ((_ble_syntax_attr[i]=(ctx==_ble_ctx_CMDX||ctx==_ble_ctx_CMDXV||ctx==_ble_ctx_CMDXE||ctx==_ble_ctx_ARGX||ctx==_ble_ctx_ARGX0||ctx==_ble_ctx_ARGVX||ctx==_ble_ctx_ARGEX)?attr:_ble_attr_ERR, + i+=1)) + ble/syntax/parse/nest-pop + return 0 + fi + fi + return 1 +} +_ble_syntax_bash_command_BeginCtx=() +_ble_syntax_bash_command_BeginCtx[_ble_ctx_ARGX]=$_ble_ctx_ARGI +_ble_syntax_bash_command_BeginCtx[_ble_ctx_ARGX0]=$_ble_ctx_ARGI +_ble_syntax_bash_command_BeginCtx[_ble_ctx_ARGVX]=$_ble_ctx_ARGVI +_ble_syntax_bash_command_BeginCtx[_ble_ctx_ARGEX]=$_ble_ctx_ARGEI +_ble_syntax_bash_command_BeginCtx[_ble_ctx_CMDX]=$_ble_ctx_CMDI +_ble_syntax_bash_command_BeginCtx[_ble_ctx_CMDX1]=$_ble_ctx_CMDI +_ble_syntax_bash_command_BeginCtx[_ble_ctx_CMDXT]=$_ble_ctx_CMDI +_ble_syntax_bash_command_BeginCtx[_ble_ctx_CMDXC]=$_ble_ctx_CMDI +_ble_syntax_bash_command_BeginCtx[_ble_ctx_CMDXE]=$_ble_ctx_CMDI +_ble_syntax_bash_command_BeginCtx[_ble_ctx_CMDXD]=$_ble_ctx_CMDI +_ble_syntax_bash_command_BeginCtx[_ble_ctx_CMDXD0]=$_ble_ctx_CMDI +_ble_syntax_bash_command_BeginCtx[_ble_ctx_CMDXV]=$_ble_ctx_CMDI +_ble_syntax_bash_command_BeginCtx[_ble_ctx_FARGX1]=$_ble_ctx_FARGI1 +_ble_syntax_bash_command_BeginCtx[_ble_ctx_SARGX1]=$_ble_ctx_FARGI1 +_ble_syntax_bash_command_BeginCtx[_ble_ctx_FARGX2]=$_ble_ctx_FARGI2 +_ble_syntax_bash_command_BeginCtx[_ble_ctx_FARGX3]=$_ble_ctx_FARGI3 +_ble_syntax_bash_command_BeginCtx[_ble_ctx_CARGX1]=$_ble_ctx_CARGI1 +_ble_syntax_bash_command_BeginCtx[_ble_ctx_CARGX2]=$_ble_ctx_CARGI2 +_ble_syntax_bash_command_BeginCtx[_ble_ctx_CPATX]=$_ble_ctx_CPATI +_ble_syntax_bash_command_BeginCtx[_ble_ctx_CPATX0]=$_ble_ctx_CPATI +_ble_syntax_bash_command_BeginCtx[_ble_ctx_TARGX1]=$_ble_ctx_TARGI1 +_ble_syntax_bash_command_BeginCtx[_ble_ctx_TARGX2]=$_ble_ctx_TARGI2 +_ble_syntax_bash_command_BeginCtx[_ble_ctx_COARGX]=$_ble_ctx_COARGI +_ble_syntax_bash_command_isARGI[_ble_ctx_CMDI]=1 +_ble_syntax_bash_command_isARGI[_ble_ctx_VRHS]=1 +_ble_syntax_bash_command_isARGI[_ble_ctx_ARGI]=1 +_ble_syntax_bash_command_isARGI[_ble_ctx_ARGQ]=1 +_ble_syntax_bash_command_isARGI[_ble_ctx_ARGVI]=1 +_ble_syntax_bash_command_isARGI[_ble_ctx_ARGVR]=1 +_ble_syntax_bash_command_isARGI[_ble_ctx_ARGEI]=1 +_ble_syntax_bash_command_isARGI[_ble_ctx_ARGER]=1 +_ble_syntax_bash_command_isARGI[_ble_ctx_FARGI1]=1 # var +_ble_syntax_bash_command_isARGI[_ble_ctx_FARGI2]=1 # in +_ble_syntax_bash_command_isARGI[_ble_ctx_FARGI3]=1 # args... +_ble_syntax_bash_command_isARGI[_ble_ctx_FARGQ3]=1 # args... (= の後) +_ble_syntax_bash_command_isARGI[_ble_ctx_CARGI1]=1 # value +_ble_syntax_bash_command_isARGI[_ble_ctx_CARGQ1]=1 # value (= の後) +_ble_syntax_bash_command_isARGI[_ble_ctx_CARGI2]=1 # in +_ble_syntax_bash_command_isARGI[_ble_ctx_CPATI]=1 # pattern +_ble_syntax_bash_command_isARGI[_ble_ctx_CPATQ]=1 # pattern +_ble_syntax_bash_command_isARGI[_ble_ctx_TARGI1]=1 # -p +_ble_syntax_bash_command_isARGI[_ble_ctx_TARGI2]=1 # -- +_ble_syntax_bash_command_isARGI[_ble_ctx_COARGI]=1 # var (coproc の後) +function ble/syntax:bash/ctx-command/.check-word-begin { + if ((wbegin<0)); then + local octx + ((octx=ctx, + wtype=octx, + ctx=_ble_syntax_bash_command_BeginCtx[ctx])) + ble/util/assert '((ctx!=0))' "invalid ctx=$octx at the beginning of words" || + ((ctx=wtype=_ble_ctx_ARGI)) + ble/syntax/parse/word-push "$wtype" "$i" + ((octx!=_ble_ctx_ARGX0&&octx!=_ble_ctx_CPATX0)); return "$?" # return unexpectedWbegin + fi + ble/util/assert '((_ble_syntax_bash_command_isARGI[ctx]))' "invalid ctx=$ctx in words" + return 0 +} +function ble/syntax:bash/ctx-command { + if ble/syntax:bash/starts-with-delimiter-or-redirect; then + ble/util/assert ' + ((ctx==_ble_ctx_ARGX||ctx==_ble_ctx_ARGX0||ctx==_ble_ctx_ARGVX||ctx==_ble_ctx_ARGEX|| + ctx==_ble_ctx_FARGX2||ctx==_ble_ctx_FARGX3||ctx==_ble_ctx_COARGX|| + ctx==_ble_ctx_CMDX||ctx==_ble_ctx_CMDX1||ctx==_ble_ctx_CMDXT||ctx==_ble_ctx_CMDXC|| + ctx==_ble_ctx_CMDXE||ctx==_ble_ctx_CMDXD||ctx==_ble_ctx_CMDXD0||ctx==_ble_ctx_CMDXV))' "invalid ctx=$ctx @ i=$i" + ble/util/assert '((wbegin<0&&wtype<0))' "invalid word-context (wtype=$wtype wbegin=$wbegin) on non-word char." + ble/syntax:bash/ctx-command/.check-delimiter-or-redirect; return "$?" + fi + ble/syntax:bash/check-comment && return 0 + local unexpectedWbegin=-1 + ble/syntax:bash/ctx-command/.check-word-begin || ((unexpectedWbegin=i)) + local wtype0=$wtype i0=$i + local flagConsume=0 + if ble/syntax:bash/check-variable-assignment; then + flagConsume=1 + elif local rex='^([^'${_ble_syntax_bash_chars[_ble_ctx_ARGI]}']+|\\.)'; [[ $tail =~ $rex ]]; then + local rematch=$BASH_REMATCH + local attr=$ctx + [[ $BASH_REMATCH == '\'? ]] && attr=$_ble_attr_QESC + ((_ble_syntax_attr[i]=attr,i+=${#rematch})) + flagConsume=1 + elif ble/syntax:bash/check-process-subst; then + flagConsume=1 + elif ble/syntax:bash/check-quotes; then + flagConsume=1 + elif ble/syntax:bash/check-dollar; then + flagConsume=1 + elif ble/syntax:bash/check-glob; then + flagConsume=1 + elif ble/syntax:bash/check-brace-expansion; then + flagConsume=1 + elif ble/syntax:bash/check-tilde-expansion; then + flagConsume=1 + elif ble/syntax:bash/starts-with-histchars; then + ble/syntax:bash/check-history-expansion || + ((_ble_syntax_attr[i]=ctx,i++)) + flagConsume=1 + fi + if ((flagConsume)); then + ble/util/assert '((wtype0>=0))' + if ((ctx==_ble_ctx_FARGI1)); then + local rex='^[a-zA-Z_][a-zA-Z_0-9]*$' attr=$_ble_attr_ERR + if ((i0==wbegin)) && [[ ${text:i0:i-i0} =~ $rex ]]; then + local ret; ble/syntax/highlight/vartype "$BASH_REMATCH"; attr=$ret + fi + ((_ble_syntax_attr[i0]=attr)) + fi + [[ ${_ble_syntax_bash_command_Expect[wtype0]} ]] && + ((_ble_syntax_attr[i0]=_ble_attr_ERR)) + if ((unexpectedWbegin>=0)); then + ble/syntax/parse/touch-updated-attr "$unexpectedWbegin" + ((_ble_syntax_attr[unexpectedWbegin]=_ble_attr_ERR)) + fi + return 0 + else + return 1 + fi +} +function ble/syntax:bash/ctx-command-compound-expect { + ble/util/assert '((ctx==_ble_ctx_FARGX1||ctx==_ble_ctx_SARGX1||ctx==_ble_ctx_CARGX1||ctx==_ble_ctx_FARGX2||ctx==_ble_ctx_CARGX2||ctx==_ble_ctx_COARGX))' + local _ble_syntax_bash_is_command_form_for= + if ble/syntax:bash/starts-with-delimiter-or-redirect; then + if ((ctx==_ble_ctx_FARGX2)) && [[ $tail == [$';\n']* ]]; then + ble/syntax:bash/ctx-command + return "$?" + elif ((ctx==_ble_ctx_FARGX1)) && [[ $tail == '(('* ]]; then + ((ctx=_ble_ctx_CMDX1,_ble_syntax_bash_is_command_form_for=1)) + elif [[ $tail == $'\n'* ]]; then + if ((ctx==_ble_ctx_CARGX2)); then + ((_ble_syntax_attr[i++]=_ble_ctx_ARGX)) + else + ((_ble_syntax_attr[i++]=_ble_attr_ERR,ctx=_ble_ctx_ARGX)) + fi + return 0 + elif [[ $tail =~ ^$_ble_syntax_bash_RexSpaces ]]; then + ((_ble_syntax_attr[i]=ctx,i+=${#BASH_REMATCH})) + return 0 + elif ((ctx!=_ble_ctx_COARGX)); then + local i0=$i + ((ctx=_ble_ctx_ARGX)) + ble/syntax:bash/ctx-command/.check-delimiter-or-redirect || ((i++)) + ((_ble_syntax_attr[i0]=_ble_attr_ERR)) + return 0 + fi + fi + local i0=$i + if ble/syntax:bash/check-comment; then + if ((ctx==_ble_ctx_FARGX1||ctx==_ble_ctx_SARGX1||ctx==_ble_ctx_CARGX1||ctx==_ble_ctx_COARGX)); then + ((_ble_syntax_attr[i0]=_ble_attr_ERR)) + fi + return 0 + fi + ble/syntax:bash/ctx-command +} +function ble/syntax:bash/ctx-command-expect/.match-word { + local word=$1 len=${#1} + if [[ $tail == "$word"* ]]; then + ble/syntax/parse/set-lookahead $((len+1)) + if ((${#tail}==len)) || i=$((i+len)) ble/syntax:bash/check-word-end/is-delimiter; then + return 0 + fi + fi + return 1 +} +function ble/syntax:bash/ctx-command-time-expect { + ble/util/assert '((ctx==_ble_ctx_TARGX1||ctx==_ble_ctx_TARGX2))' + if ble/syntax:bash/starts-with-delimiter-or-redirect; then + ble/util/assert '((wbegin<0&&wtype<0))' + if [[ $tail =~ ^$_ble_syntax_bash_RexSpaces ]]; then + ((_ble_syntax_attr[i]=ctx,i+=${#BASH_REMATCH})) + return 0 + else + ((ctx=_ble_ctx_CMDXT)) + ble/syntax:bash/ctx-command/.check-delimiter-or-redirect; return "$?" + fi + fi + if ((ctx==_ble_ctx_TARGX1)); then + ble/syntax:bash/ctx-command-expect/.match-word '-p' || + ((ctx=_ble_bash>=50100?_ble_ctx_TARGX2:_ble_ctx_CMDXT)) + fi + if ((ctx==_ble_ctx_TARGX2)); then + ble/syntax:bash/ctx-command-expect/.match-word '--' || + ((ctx=_ble_ctx_CMDXT)) + fi + ble/syntax:bash/ctx-command +} +function ble/syntax:bash/ctx-command-case-pattern-expect { + ble/util/assert '((ctx==_ble_ctx_CPATX||ctx==_ble_ctx_CPATX0))' + if ble/syntax:bash/starts-with-delimiter-or-redirect; then + local delimiter=$BASH_REMATCH + if [[ $tail =~ ^$_ble_syntax_bash_RexSpaces ]]; then + ((_ble_syntax_attr[i]=ctx,i+=${#BASH_REMATCH})) + elif [[ $tail == '|'* ]]; then + ((_ble_syntax_attr[i++]=ctx==_ble_ctx_CPATX?_ble_attr_ERR:_ble_attr_GLOB,ctx=_ble_ctx_CPATX)) + elif [[ $tail == ')'* ]]; then + ((_ble_syntax_attr[i++]=ctx==_ble_ctx_CPATX?_ble_attr_ERR:_ble_attr_GLOB,ctx=_ble_ctx_CMDX)) + elif [[ $tail == '('* ]]; then + ble/syntax:bash/ctx-command/.check-delimiter-or-redirect + else + ((_ble_syntax_attr[i]=_ble_attr_ERR,i+=${#delimiter})) + fi + return "$?" + fi + local i0=$i + if ble/syntax:bash/check-comment; then + ((_ble_syntax_attr[i0]=_ble_attr_ERR)) + return 0 + fi + ble/syntax:bash/ctx-command +} +_BLE_SYNTAX_FCTX[_ble_ctx_VALX]=ble/syntax:bash/ctx-values +_BLE_SYNTAX_FCTX[_ble_ctx_VALI]=ble/syntax:bash/ctx-values +_BLE_SYNTAX_FEND[_ble_ctx_VALI]=ble/syntax:bash/ctx-values/check-word-end +_BLE_SYNTAX_FCTX[_ble_ctx_VALR]=ble/syntax:bash/ctx-values +_BLE_SYNTAX_FEND[_ble_ctx_VALR]=ble/syntax:bash/ctx-values/check-word-end +_BLE_SYNTAX_FCTX[_ble_ctx_VALQ]=ble/syntax:bash/ctx-values +_BLE_SYNTAX_FEND[_ble_ctx_VALQ]=ble/syntax:bash/ctx-values/check-word-end +function ble/syntax:bash/ctx-values/enter { + local outer_nparam=$nparam + ble/syntax/parse/nest-push "$_ble_ctx_VALX" + nparam=$outer_nparam +} +function ble/syntax:bash/ctx-values/leave { + local inner_nparam=$nparam + ble/syntax/parse/nest-pop + nparam=$inner_nparam +} +function ble/syntax:bash/ctx-values/check-word-end { + ((wbegin<0)) && return 1 + [[ ${text:i:1} == [!"$_ble_term_IFS;|&<>()"] ]] && return 1 + local wbeg=$wbegin wlen=$((i-wbegin)) wend=$i + local word=${text:wbegin:wlen} + ble/syntax/parse/word-pop + ble/util/assert '((ctx==_ble_ctx_VALI||ctx==_ble_ctx_VALR||ctx==_ble_ctx_VALQ))' 'invalid context' + ((ctx=_ble_ctx_VALX)) + return 0 +} +function ble/syntax:bash/ctx-values { + if ble/syntax:bash/starts-with-delimiter; then + ble/util/assert '((ctx==_ble_ctx_VALX))' "invalid ctx=$ctx @ i=$i" + ble/util/assert '((wbegin<0&&wtype<0))' "invalid word-context (wtype=$wtype wbegin=$wbegin) on non-word char." + if [[ $tail =~ ^$_ble_syntax_bash_RexIFSs ]]; then + local spaces=$BASH_REMATCH + ble/syntax:bash/check-here-document-from "$spaces" && return 0 + ((_ble_syntax_attr[i]=ctx,i+=${#spaces})) + return 0 + elif [[ $tail == ')'* ]]; then + ((_ble_syntax_attr[i++]=_ble_attr_DEL)) + ble/syntax:bash/ctx-values/leave + return 0 + elif [[ $type == ';'* ]]; then + ((_ble_syntax_attr[i++]=_ble_attr_ERR)) + return 0 + else + ((_ble_syntax_attr[i++]=_ble_attr_ERR)) + return 0 + fi + fi + if ble/syntax:bash/check-comment; then + return 0 + fi + if ((wbegin<0)); then + ((ctx=_ble_ctx_VALI)) + ble/syntax/parse/word-push "$ctx" "$i" + fi + ble/util/assert '((ctx==_ble_ctx_VALI||ctx==_ble_ctx_VALR||ctx==_ble_ctx_VALQ))' "invalid context ctx=$ctx" + if ble/syntax:bash/check-variable-assignment; then + return 0 + elif ble/syntax:bash/check-plain-with-escape "[^${_ble_syntax_bash_chars[_ble_ctx_ARGI]}]+"; then + return 0 + elif ble/syntax:bash/check-process-subst; then + return 0 + elif ble/syntax:bash/check-quotes; then + return 0 + elif ble/syntax:bash/check-dollar; then + return 0 + elif ble/syntax:bash/check-glob; then + return 0 + elif ble/syntax:bash/check-brace-expansion; then + return 0 + elif ble/syntax:bash/check-tilde-expansion; then + return 0 + elif ble/syntax:bash/starts-with-histchars; then + ble/syntax:bash/check-history-expansion || + ((_ble_syntax_attr[i]=ctx,i++)) + return 0 + fi + return 1 +} +_BLE_SYNTAX_FCTX[_ble_ctx_CONDX]=ble/syntax:bash/ctx-conditions +_BLE_SYNTAX_FCTX[_ble_ctx_CONDI]=ble/syntax:bash/ctx-conditions +_BLE_SYNTAX_FEND[_ble_ctx_CONDI]=ble/syntax:bash/ctx-conditions/check-word-end +_BLE_SYNTAX_FCTX[_ble_ctx_CONDQ]=ble/syntax:bash/ctx-conditions +_BLE_SYNTAX_FEND[_ble_ctx_CONDQ]=ble/syntax:bash/ctx-conditions/check-word-end +function ble/syntax:bash/ctx-conditions/check-word-end { + ((wbegin<0)) && return 1 + [[ ${text:i:1} == [!"$_ble_term_IFS;|&<>()"] ]] && return 1 + local wbeg=$wbegin wlen=$((i-wbegin)) wend=$i + local word=${text:wbegin:wlen} + ble/syntax/parse/word-pop + ble/util/assert '((ctx==_ble_ctx_CONDI||ctx==_ble_ctx_CONDQ))' 'invalid context' + if [[ $word == ']]' ]]; then + ble/syntax/parse/touch-updated-attr "$wbeg" + ((_ble_syntax_attr[wbeg]=_ble_attr_DEL)) + ble/syntax/parse/nest-pop + else + ((ctx=_ble_ctx_CONDX)) + fi + return 0 +} +function ble/syntax:bash/ctx-conditions { + if ble/syntax:bash/starts-with-delimiter; then + ble/util/assert '((ctx==_ble_ctx_CONDX))' "invalid ctx=$ctx @ i=$i" + ble/util/assert '((wbegin<0&&wtype<0))' "invalid word-context (wtype=$wtype wbegin=$wbegin) on non-word char." + if [[ $tail =~ ^$_ble_syntax_bash_RexIFSs ]]; then + ((_ble_syntax_attr[i]=ctx,i+=${#BASH_REMATCH})) + return 0 + else + ((_ble_syntax_attr[i++]=_ble_ctx_CONDI)) + return 0 + fi + fi + ble/syntax:bash/check-comment && return 0 + if ((wbegin<0)); then + ((ctx=_ble_ctx_CONDI)) + ble/syntax/parse/word-push "$ctx" "$i" + fi + ble/util/assert '((ctx==_ble_ctx_CONDI||ctx==_ble_ctx_CONDQ))' "invalid context ctx=$ctx" + if ble/syntax:bash/check-variable-assignment; then + return 0 + elif ble/syntax:bash/check-plain-with-escape "[^${_ble_syntax_bash_chars[_ble_ctx_ARGI]}]+"; then + return 0 + elif ble/syntax:bash/check-process-subst; then + return 0 + elif ble/syntax:bash/check-quotes; then + return 0 + elif ble/syntax:bash/check-dollar; then + return 0 + elif ble/syntax:bash/check-glob; then + return 0 + elif ble/syntax:bash/check-brace-expansion; then + return 0 + elif ble/syntax:bash/check-tilde-expansion; then + return 0 + elif ble/syntax:bash/starts-with-histchars; then + ble/syntax:bash/check-history-expansion || + ((_ble_syntax_attr[i++]=ctx)) + return 0 + else + ((_ble_syntax_attr[i++]=ctx)) + return 0 + fi + return 1 +} +_BLE_SYNTAX_FCTX[_ble_ctx_RDRF]=ble/syntax:bash/ctx-redirect +_BLE_SYNTAX_FCTX[_ble_ctx_RDRD]=ble/syntax:bash/ctx-redirect +_BLE_SYNTAX_FCTX[_ble_ctx_RDRD2]=ble/syntax:bash/ctx-redirect +_BLE_SYNTAX_FCTX[_ble_ctx_RDRS]=ble/syntax:bash/ctx-redirect +_BLE_SYNTAX_FEND[_ble_ctx_RDRF]=ble/syntax:bash/ctx-redirect/check-word-end +_BLE_SYNTAX_FEND[_ble_ctx_RDRD]=ble/syntax:bash/ctx-redirect/check-word-end +_BLE_SYNTAX_FEND[_ble_ctx_RDRD2]=ble/syntax:bash/ctx-redirect/check-word-end +_BLE_SYNTAX_FEND[_ble_ctx_RDRS]=ble/syntax:bash/ctx-redirect/check-word-end +function ble/syntax:bash/ctx-redirect/check-word-begin { + if ((wbegin<0)); then + ble/syntax/parse/word-push "$ctx" "$i" + ble/syntax/parse/touch-updated-word "$i" #■これは不要では? + fi +} +function ble/syntax:bash/ctx-redirect/check-word-end { + ((wbegin<0)) && return 1 + ble/syntax:bash/check-word-end/is-delimiter || return 1 + ble/syntax/parse/word-pop + ble/syntax/parse/nest-pop + ble/util/assert '((!_ble_syntax_bash_command_isARGI[ctx]))' "invalid ctx=$ctx in words" + return 0 +} +function ble/syntax:bash/ctx-redirect { + if ble/syntax:bash/starts-with-delimiter-or-redirect; then + ((_ble_syntax_attr[i++]=_ble_attr_ERR)) + [[ ${tail:1} =~ ^$_ble_syntax_bash_RexSpaces ]] && + ((_ble_syntax_attr[i]=ctx,i+=${#BASH_REMATCH})) + return 0 + fi + if local i0=$i; ble/syntax:bash/check-comment; then + ((_ble_syntax_attr[i0]=_ble_attr_ERR)) + return 0 + fi + ble/syntax:bash/ctx-redirect/check-word-begin + if ble/syntax:bash/check-plain-with-escape "[^${_ble_syntax_bash_chars[_ble_ctx_ARGI]}]+"; then + return 0 + elif ble/syntax:bash/check-process-subst; then + return 0 + elif ble/syntax:bash/check-quotes; then + return 0 + elif ble/syntax:bash/check-dollar; then + return 0 + elif ble/syntax:bash/check-glob; then + return 0 + elif ble/syntax:bash/check-brace-expansion; then + return 0 + elif ble/syntax:bash/check-tilde-expansion; then + return 0 + elif ble/syntax:bash/starts-with-histchars; then + ble/syntax:bash/check-history-expansion || + ((_ble_syntax_attr[i]=ctx,i++)) + return 0 + fi + return 1 +} +_ble_syntax_bash_heredoc_EscSP='\040' +_ble_syntax_bash_heredoc_EscHT='\011' +_ble_syntax_bash_heredoc_EscLF='\012' +_ble_syntax_bash_heredoc_EscFS='\034' +function ble/syntax:bash/ctx-heredoc-word/initialize { + local ret + ble/util/s2c ' ' + ble/util/sprintf _ble_syntax_bash_heredoc_EscSP '\\%03o' "$ret" + ble/util/s2c $'\t' + ble/util/sprintf _ble_syntax_bash_heredoc_EscHT '\\%03o' "$ret" + ble/util/s2c $'\n' + ble/util/sprintf _ble_syntax_bash_heredoc_EscLF '\\%03o' "$ret" + ble/util/s2c "$_ble_term_FS" + ble/util/sprintf _ble_syntax_bash_heredoc_EscFS '\\%03o' "$ret" +} +ble/syntax:bash/ctx-heredoc-word/initialize +function ble/syntax:bash/ctx-heredoc-word/remove-quotes { + local text=$1 result= + local rex='^[^\$"'\'']+|^\$?["'\'']|^\\.?|^.' + while [[ $text && $text =~ $rex ]]; do + local rematch=$BASH_REMATCH + if [[ $rematch == \" || $rematch == \$\" ]]; then + if rex='^\$?"(([^\"]|\\.)*)(\\?$|")'; [[ $text =~ $rex ]]; then + local str=${BASH_REMATCH[1]} + local a b + b='\`' a='`'; str=${str//"$b"/"$a"} + b='\"' a='"'; str=${str//"$b"/"$a"} # WA #D1751 safe + b='\$' a='$'; str=${str//"$b"/"$a"} + b='\\' a='\'; str=${str//"$b"/"$a"} + result=$result$str + text=${text:${#BASH_REMATCH}} + continue + fi + elif [[ $rematch == \' ]]; then + if rex="^('[^']*)'?"; [[ $text =~ $rex ]]; then + builtin eval "result=\$result${BASH_REMATCH[1]}'" + text=${text:${#BASH_REMATCH}} + continue + fi + elif [[ $rematch == \$\' ]]; then + if rex='^(\$'\''([^\'\'']|\\.)*)('\''|\\?$)'; [[ $text =~ $rex ]]; then + builtin eval "result=\$result${BASH_REMATCH[1]}'" + text=${text:${#BASH_REMATCH}} + continue + fi + elif [[ $rematch == \\* ]]; then + result=$result${rematch:1} + text=${text:${#rematch}} + continue + fi + result=$result$rematch + text=${text:${#rematch}} + done + delimiter=$result$text +} +function ble/syntax:bash/ctx-heredoc-word/escape-delimiter { + local ret=$1 + if [[ $ret == *[\\\'$_ble_term_IFS$_ble_term_FS]* ]]; then + local a b fs=$_ble_term_FS + a=\\ ; b='\'$a; ret=${ret//"$a"/"$b"} + a=\' ; b='\'$a; ret=${ret//"$a"/"$b"} + a=' ' ; b=$_ble_syntax_bash_heredoc_EscSP; ret=${ret//"$a"/"$b"} + a=$'\t'; b=$_ble_syntax_bash_heredoc_EscHT; ret=${ret//"$a"/"$b"} + a=$'\n'; b=$_ble_syntax_bash_heredoc_EscLF; ret=${ret//"$a"/"$b"} + a=$fs ; b=$_ble_syntax_bash_heredoc_EscFS; ret=${ret//"$a"/"$b"} + fi + escaped=$ret +} +function ble/syntax:bash/ctx-heredoc-word/unescape-delimiter { + builtin eval "delimiter=\$'$1'" +} +_BLE_SYNTAX_FCTX[_ble_ctx_RDRH]=ble/syntax:bash/ctx-heredoc-word +_BLE_SYNTAX_FEND[_ble_ctx_RDRH]=ble/syntax:bash/ctx-heredoc-word/check-word-end +_BLE_SYNTAX_FCTX[_ble_ctx_RDRI]=ble/syntax:bash/ctx-heredoc-word +_BLE_SYNTAX_FEND[_ble_ctx_RDRI]=ble/syntax:bash/ctx-heredoc-word/check-word-end +function ble/syntax:bash/ctx-heredoc-word/check-word-end { + ((wbegin<0)) && return 1 + ble/syntax:bash/check-word-end/is-delimiter || return 1 + local octx=$ctx word=${text:wbegin:i-wbegin} + ble/syntax/parse/word-pop + ble/syntax/parse/nest-pop + local I + if ((octx==_ble_ctx_RDRI)); then I=I; else I=R; fi + local Q delimiter + if [[ $word == *[\'\"\\]* ]]; then + Q=Q; ble/syntax:bash/ctx-heredoc-word/remove-quotes "$word" + else + Q=H; delimiter=$word + fi + local escaped; ble/syntax:bash/ctx-heredoc-word/escape-delimiter "$delimiter" + nparam=$nparam$_ble_term_FS@$I$Q$escaped + return 0 +} +function ble/syntax:bash/ctx-heredoc-word { + ble/syntax:bash/ctx-redirect +} +_BLE_SYNTAX_FCTX[_ble_ctx_HERE0]=ble/syntax:bash/ctx-heredoc-content +_BLE_SYNTAX_FCTX[_ble_ctx_HERE1]=ble/syntax:bash/ctx-heredoc-content +function ble/syntax:bash/ctx-heredoc-content { + local indented= quoted= delimiter= + ble/syntax:bash/ctx-heredoc-word/unescape-delimiter "${nparam:2}" + [[ ${nparam::1} == I ]] && indented=1 + [[ ${nparam:1:1} == Q ]] && quoted=1 + local rex ht=$'\t' lf=$'\n' + if ((ctx==_ble_ctx_HERE0)); then + rex="^${indented:+$ht*}"$'([^\n]+\n?|\n)' + [[ $tail =~ $rex ]] || return 1 + local line=${BASH_REMATCH%"$lf"} + local rematch1=${BASH_REMATCH[1]} + if [[ ${rematch1%"$lf"} == "$delimiter" ]]; then + local indent + ((indent=${#BASH_REMATCH}-${#rematch1}, + _ble_syntax_attr[i]=_ble_ctx_HERE0, + _ble_syntax_attr[i+indent]=_ble_ctx_RDRH, + i+=${#line})) + ble/syntax/parse/nest-pop + return 0 + fi + fi + if [[ $quoted ]]; then + ble/util/assert '((ctx==_ble_ctx_HERE0))' + ((_ble_syntax_attr[i]=_ble_ctx_HERE0,i+=${#BASH_REMATCH})) + return 0 + else + ((ctx=_ble_ctx_HERE1)) + if rex='^([^$`\'"$lf"']|\\.)+'"$lf"'?|^'"$lf" && [[ $tail =~ $rex ]]; then + ((_ble_syntax_attr[i]=_ble_ctx_HERE0, + i+=${#BASH_REMATCH})) + [[ $BASH_REMATCH == *"$lf" ]] && ((ctx=_ble_ctx_HERE0)) + return 0 + fi + if ble/syntax:bash/check-dollar; then + return 0 + elif [[ $tail == '`'* ]] && ble/syntax:bash/check-quotes; then + return 0 + else + ((_ble_syntax_attr[i]=_ble_ctx_HERE0,i++)) + return 0 + fi + fi +} +function ble/syntax:bash/is-complete { + local iN=${#_ble_syntax_text} + ((iN>0)) && ((_ble_syntax_attr[iN-1]==_ble_attr_ERR)) && return 1 + local stat=${_ble_syntax_stat[iN]} + if [[ $stat ]]; then + ble/string#split-words stat "$stat" + local nlen=${stat[3]}; ((nlen>=0)) && return 1 + local nparam=${stat[6]}; [[ $nparam == none ]] && nparam= + local rex="$_ble_term_FS@([RI][QH][^$_ble_term_FS]*)(.*$)" + [[ $nparam =~ $rex ]] && return 1 + local ctx=${stat[0]} + ((ctx==_ble_ctx_ARGX||ctx==_ble_ctx_ARGX0||ctx==_ble_ctx_ARGVX||ctx==_ble_ctx_ARGEX|| + ctx==_ble_ctx_CMDX||ctx==_ble_ctx_CMDXT||ctx==_ble_ctx_CMDXE||ctx==_ble_ctx_CMDXV|| + ctx==_ble_ctx_TARGX1||ctx==_ble_ctx_TARGX2)) || return 1 + fi + local attrs ret + IFS= builtin eval 'attrs="::${_ble_syntax_attr[*]/%/::}"' # WA #D1570 checked + ble/string#count-string "$attrs" ":$_ble_attr_KEYWORD_BEGIN:"; local nbeg=$ret + ble/string#count-string "$attrs" ":$_ble_attr_KEYWORD_END:"; local nend=$ret + ((nbeg>nend)) && return 1 + return 0 +} +function ble/syntax:bash/find-end-of-array-index { + local beg=$1 end=$2 + ret= + local inest0=$beg nest0 + [[ ${_ble_syntax_nest[inest0]} ]] || return 1 + local q stat1 nlen1 inest1 r= + for ((q=inest0+1;q<end;q++)); do + local stat1=${_ble_syntax_stat[q]} + [[ $stat1 ]] || continue + ble/string#split-words stat1 "$stat1" + ((nlen1=stat1[3])) # (workaround Bash-4.2 segfault) + ((inest1=nlen1<0?nlen1:q-nlen1)) + ((inest1<inest0)) && break + ((r=q)) + done + [[ ${_ble_syntax_text:r:end-r} == ']'* ]] && ret=$r + [[ $ret ]] +} +function ble/syntax:bash/find-rhs { + local wtype=$1 wbeg=$2 wlen=$3 opts=$4 + local text=$_ble_syntax_text + local word=${text:wbeg:wlen} wend=$((wbeg+wlen)) + local rex= + if ((wtype==_ble_attr_VAR)); then + rex='^[a-zA-Z0-9_]+(\+?=|\[)' + elif ((wtype==_ble_ctx_VALI)); then + if [[ :$opts: == *:element-assignment:* ]]; then + rex='^[a-zA-Z0-9_]+(\+?=|\[)|^(\[)' + else + rex='^(\[)' + fi + fi + if [[ $rex && $word =~ $rex ]]; then + local last_char=${BASH_REMATCH:${#BASH_REMATCH}-1} + if [[ $last_char == '[' ]]; then + local p1=$((wbeg+${#BASH_REMATCH}-1)) + if ble/syntax:bash/find-end-of-array-index "$p1" "$wend"; then + local p2=$ret + case ${text:p2:wend-p2} in + (']='*) ((ret=p2+2)); return 0 ;; + (']+='*) ((ret=p2+3)); return 0 ;; + esac + fi + else + ((ret=wbeg+${#BASH_REMATCH})) + return 0 + fi + fi + ret=$wbeg + return 1 +} +_ble_syntax_vanishing_word_umin=-1 +_ble_syntax_vanishing_word_umax=-1 +function ble/syntax/vanishing-word/register { + local tree_array=$1 tofs=$2 + local beg=$3 end=$4 lbeg=$5 lend=$6 + (((beg<=0)&&(beg=1))) + local node i nofs + for ((i=end;i>=beg;i--)); do + builtin eval "node=(\${$tree_array[tofs+i-1]})" + ((${#node[@]})) || continue + for ((nofs=0;nofs<${#node[@]};nofs+=_ble_syntax_TREE_WIDTH)); do + local wtype=${node[nofs]} wlen=${node[nofs+1]} + local wbeg=$((wlen<0?wlen:i-wlen)) wend=$i + ((wbeg<lbeg&&(wbeg=lbeg), + wend>lend&&(wend=lend))) + ble/syntax/urange#update _ble_syntax_vanishing_word_ "$wbeg" "$wend" + done + done +} +function ble/syntax/parse/shift.stat { + if [[ ${_ble_syntax_stat[shift2_j]} ]]; then + local -a stat; ble/string#split-words stat "${_ble_syntax_stat[shift2_j]}" + local k klen kbeg + for k in 1 3 4 5; do # wlen nlen tclen tplen + (((klen=stat[k])<0)) && continue + ((kbeg=shift2_j-klen)) + if ((kbeg<beg)); then + ((stat[k]+=shift)) + elif ((kbeg<end0)); then + ((stat[k]-=end0-kbeg)) + fi + done + _ble_syntax_stat[shift2_j]="${stat[*]}" + fi +} +function ble/syntax/parse/shift.tree/1 { + local k klen kbeg + for k in 1 2 3; do # wlen/nlen tclen tplen + ((klen=node[nofs+k])) + ((klen<0||(kbeg=shift2_j-klen)>end0)) && continue + if [[ $k == 1 && ${node[nofs]} =~ ^[0-9]$ ]]; then + ble/syntax/parse/touch-updated-word "$shift2_j" + node[nofs+4]='-' + fi + if ((kbeg<beg)); then + ((node[nofs+k]+=shift)) + elif ((kbeg<end0)); then + ((node[nofs+k]-=end0-kbeg)) + fi + done +} +function ble/syntax/parse/shift.tree { + [[ ${_ble_syntax_tree[shift2_j-1]} ]] || return 1 + local -a node + ble/string#split-words node "${_ble_syntax_tree[shift2_j-1]}" + local nofs + if [[ $1 ]]; then + nofs=$1 ble/syntax/parse/shift.tree/1 + else + for ((nofs=0;nofs<${#node[@]};nofs+=_ble_syntax_TREE_WIDTH)); do + ble/syntax/parse/shift.tree/1 + done + fi + _ble_syntax_tree[shift2_j-1]="${node[*]}" +} +function ble/syntax/parse/shift.nest { + if [[ ${_ble_syntax_nest[shift2_j]} ]]; then + local -a nest + ble/string#split-words nest "${_ble_syntax_nest[shift2_j]}" + local k klen kbeg + for k in 1 3 4 5; do + (((klen=nest[k]))) + ((klen<0||(kbeg=shift2_j-klen)<0)) && continue + if ((kbeg<beg)); then + ((nest[k]+=shift)) + elif ((kbeg<end0)); then + ((nest[k]-=end0-kbeg)) + fi + done + _ble_syntax_nest[shift2_j]="${nest[*]}" + fi +} +function ble/syntax/parse/shift.impl2/.shift-until { + local limit=$1 + while ((shift2_j>=limit)); do + [[ $bleopt_syntax_debug ]] && _ble_syntax_stat_shift[shift2_j+shift]=1 + ble/syntax/parse/shift.stat + ble/syntax/parse/shift.nest + ((shift2_j--)) + done +} +function ble/syntax/parse/shift.impl2/.proc1 { + if ((TE_i<j2)); then + ((tprev=-1)) # 中断 + return 0 + fi + ble/syntax/parse/shift.impl2/.shift-until $((TE_i+1)) + ble/syntax/parse/shift.tree "$TE_nofs" + if ((tprev>end0&&wbegin>end0)) && [[ ${wtype//[0-9]} ]]; then + [[ $bleopt_syntax_debug ]] && _ble_syntax_stat_shift[shift2_j+shift]=1 + ble/syntax/parse/shift.stat + ble/syntax/parse/shift.nest + ((shift2_j=wbegin)) # skip + elif ((tchild>=0)); then + ble/syntax/tree-enumerate-children ble/syntax/parse/shift.impl2/.proc1 + fi +} +function ble/syntax/parse/shift.method1 { + local i j + for ((i=i2,j=j2;i<=iN;i++,j++)); do + local shift2_j=$j + ble/syntax/parse/shift.stat + ((j>0)) && ble/syntax/parse/shift.tree + ((i<iN)) && ble/syntax/parse/shift.nest + done +} +function ble/syntax/parse/shift.method2 { + [[ $bleopt_syntax_debug ]] && _ble_syntax_stat_shift=() + local iN=${#_ble_syntax_text} # tree-enumerate 起点は (古い text の長さ) である + local shift2_j=$iN # proc1 に渡す変数 + ble/syntax/tree-enumerate ble/syntax/parse/shift.impl2/.proc1 + ble/syntax/parse/shift.impl2/.shift-until "$j2" # 未処理部分 +} +function ble/syntax/parse/shift { + ble/syntax/parse/shift.method2 # tree-enumerate による skip + if ((shift!=0)); then + ble/syntax/urange#shift _ble_syntax_attr_ + ble/syntax/wrange#shift _ble_syntax_word_ + ble/syntax/wrange#shift _ble_syntax_word_defer_ + ble/syntax/urange#shift _ble_syntax_vanishing_word_ + fi +} +_ble_syntax_dbeg=-1 _ble_syntax_dend=-1 +function ble/syntax/parse/determine-parse-range { + local flagSeekStat=0 + ((i1=_ble_syntax_dbeg,i1>=end0&&(i1+=shift), + i2=_ble_syntax_dend,i2>=end0&&(i2+=shift), + (i1<0||beg<i1)&&(i1=beg,flagSeekStat=1), + (i2<0||i2<end)&&(i2=end), + (i2>iN)&&(i2=iN), + j2=i2-shift)) + if ((flagSeekStat)); then + local lookahead='stat[7]' + local -a stat + while ((i1>0)); do + if [[ ${_ble_syntax_stat[--i1]} ]]; then + ble/string#split-words stat "${_ble_syntax_stat[i1]}" + ((i1+lookahead<=beg)) && break + fi + done + fi + ble/util/assert '((0<=i1&&i1<=beg&&end<=i2&&i2<=iN))' "X2 0 <= $i1 <= $beg <= $end <= $i2 <= $iN" +} +function ble/syntax/parse/check-end { + [[ ${_BLE_SYNTAX_FEND[ctx]} ]] && "${_BLE_SYNTAX_FEND[ctx]}" +} +function ble/syntax/parse { + local text=$1 iN=${#1} + local opts=$2 + local beg=${3:-0} end=${4:-$iN} end0=${5:-0} + ((end==beg&&end0==beg&&_ble_syntax_dbeg<0)) && return 0 + local IFS=$_ble_term_IFS + local shift=$((end-end0)) + ble/util/assert \ + '((0<=beg&&beg<=end&&end<=iN&&beg<=end0))' \ + "X1 0 <= beg:$beg <= end:$end <= iN:$iN, beg:$beg <= end0:$end0 (shift=$shift text=$text)" || + ((beg=0,end=iN)) + local i1 i2 j2 + ble/syntax/parse/determine-parse-range + ble/syntax/vanishing-word/register _ble_syntax_tree 0 "$i1" "$j2" 0 "$i2" + ble/syntax/parse/shift + local ctx wbegin wtype inest tchild tprev nparam ilook + if ((i1>0)) && [[ ${_ble_syntax_stat[i1]} ]]; then + local -a stat + ble/string#split-words stat "${_ble_syntax_stat[i1]}" + local wlen=${stat[1]} nlen=${stat[3]} tclen=${stat[4]} tplen=${stat[5]} + ctx=${stat[0]} + wbegin=$((wlen<0?wlen:i1-wlen)) + wtype=${stat[2]} + inest=$((nlen<0?nlen:i1-nlen)) + tchild=$((tclen<0?tclen:i1-tclen)) + tprev=$((tplen<0?tplen:i1-tplen)) + nparam=${stat[6]}; [[ $nparam == none ]] && nparam= + ilook=$((i1+${stat[7]:-1})) + else + ctx=$_ble_ctx_UNSPECIFIED ##!< 現在の解析の文脈 + ble/syntax:"$_ble_syntax_lang"/initialize-ctx # ctx 初期化 + wbegin=-1 ##!< シェル単語内にいる時、シェル単語の開始位置 + wtype=-1 ##!< シェル単語内にいる時、シェル単語の種類 + inest=-1 ##!< 入れ子の時、親の開始位置 + tchild=-1 + tprev=-1 + nparam= + ilook=1 + fi + local -a _tail_syntax_stat _tail_syntax_tree _tail_syntax_nest _tail_syntax_attr + _tail_syntax_stat=("${_ble_syntax_stat[@]:j2:iN-i2+1}") + _tail_syntax_tree=("${_ble_syntax_tree[@]:j2:iN-i2}") + _tail_syntax_nest=("${_ble_syntax_nest[@]:j2:iN-i2}") + _tail_syntax_attr=("${_ble_syntax_attr[@]:j2:iN-i2}") + ble/array#reserve-prototype "$iN" + _ble_syntax_stat=("${_ble_syntax_stat[@]::i1}" "${_ble_array_prototype[@]:i1:iN-i1}") # 再開用データ + _ble_syntax_tree=("${_ble_syntax_tree[@]::i1}" "${_ble_array_prototype[@]:i1:iN-i1}") # 単語 + _ble_syntax_nest=("${_ble_syntax_nest[@]::i1}" "${_ble_array_prototype[@]:i1:iN-i1}") # 入れ子の親 + _ble_syntax_attr=("${_ble_syntax_attr[@]::i1}" "${_ble_array_prototype[@]:i1:iN-i1}") # 文脈・色とか + ble/syntax:"$_ble_syntax_lang"/initialize-vars + _ble_syntax_text=$text + local i _stat tail + local debug_p1 + for ((i=i1;i<iN;)); do + ble/syntax/parse/generate-stat + if ((i>=i2)) && [[ ${_tail_syntax_stat[i-i2]} == "$_stat" ]]; then + if ble/syntax/parse/nest-equals "$inest"; then + _ble_syntax_stat=("${_ble_syntax_stat[@]::i}" "${_tail_syntax_stat[@]:i-i2}") + _ble_syntax_tree=("${_ble_syntax_tree[@]::i}" "${_tail_syntax_tree[@]:i-i2}") + _ble_syntax_nest=("${_ble_syntax_nest[@]::i}" "${_tail_syntax_nest[@]:i-i2}") + _ble_syntax_attr=("${_ble_syntax_attr[@]::i}" "${_tail_syntax_attr[@]:i-i2}") + break + fi + fi + _ble_syntax_stat[i]=$_stat + tail=${text:i} + debug_p1=$i + "${_BLE_SYNTAX_FCTX[ctx]}" || ((_ble_syntax_attr[i]=_ble_attr_ERR,i++)) + ble/syntax/parse/check-end + done + builtin unset -v debug_p1 + ble/syntax/vanishing-word/register _tail_syntax_tree $((-i2)) $((i2+1)) "$i" 0 "$i" + ble/syntax/urange#update _ble_syntax_attr_ "$i1" "$i" + (((i>=i2)?( + _ble_syntax_dbeg=_ble_syntax_dend=-1 + ):( + _ble_syntax_dbeg=i,_ble_syntax_dend=i2))) + if ((i>=iN)); then + ((i=iN)) + ble/syntax/parse/generate-stat + _ble_syntax_stat[i]=$_stat + if ((inest>0)); then + ((_ble_syntax_attr[iN-1]=_ble_attr_ERR)) + while ((inest>=0)); do + ((i=inest)) + ble/syntax/parse/nest-pop + ((inest>=i&&(inest=i-1))) + done + fi + fi + ble/util/assert \ + '((${#_ble_syntax_stat[@]}==iN+1))' \ + "unexpected array length #arr=${#_ble_syntax_stat[@]} (expected to be $iN), #proto=${#_ble_array_prototype[@]} should be >= $iN" +} +function ble/syntax/highlight { + local text=$1 lang=${2:-bash} cache_prefix=$3 + local -a _ble_highlight_layer__list=(plain syntax) + local -a vars=() + ble/array#push vars "${_ble_syntax_VARNAMES[@]}" + ble/array#push vars "${_ble_highlight_layer_plain_VARNAMES[@]}" + ble/array#push vars "${_ble_highlight_layer_syntax_VARNAMES[@]}" + local "${vars[@]/%/=}" # WA #D1570 checked + if [[ $cache_prefix ]] && ((${cache_prefix}_INITIALIZED++)); then + ble/util/restore-vars "$cache_prefix" "${vars[@]}" + ble/string#common-prefix "$_ble_syntax_text" "$text" + local beg=${#ret} + ble/string#common-suffix "${_ble_syntax_text:beg}" "${text:beg}" + local end=$((${#text}-${#ret})) end0=$((${#_ble_syntax_text}-${#ret})) + else + ble/syntax/initialize-vars + ble/highlight/layer:plain/initialize-vars + ble/highlight/layer:syntax/initialize-vars + _ble_syntax_lang=$lang + local beg=0 end=${#text} end0=0 + fi + ble/syntax/parse "$text" '' "$beg" "$end" "$end0" + local HIGHLIGHT_BUFF HIGHLIGHT_UMIN HIGHLIGHT_UMAX + ble/highlight/layer/update "$text" '' "$beg" "$end" "$end0" + IFS= builtin eval "ret=\"\${$HIGHLIGHT_BUFF[*]}\"" + [[ $cache_prefix ]] && + ble/util/save-vars "$cache_prefix" "${vars[@]}" + return 0 +} +function ble/syntax/completion-context/.add { + local source=$1 + local comp1=$2 + ble/util/assert '[[ $source && comp1 -ge 0 ]]' + sources[${#sources[*]}]="$source $comp1" +} +function ble/syntax/completion-context/.check/parameter-expansion { + local rex_paramx='^(\$(\{[!#]?)?)([a-zA-Z_][a-zA-Z_0-9]*)?$' + if [[ ${text:istat:index-istat} =~ $rex_paramx ]]; then + local rematch1=${BASH_REMATCH[1]} + local source=variable + if [[ $rematch1 == '${'* ]]; then + source=variable:b # suffix } + elif ((ctx==_ble_ctx_BRACE1||ctx==_ble_ctx_BRACE2)); then + source=variable:n # no suffix + fi + ble/syntax/completion-context/.add "$source" $((istat+${#rematch1})) + fi +} +_ble_syntax_bash_complete_check_prefix[_ble_ctx_CMDI]=inside-command +function ble/syntax/completion-context/.check-prefix/ctx:inside-command { + if ((wlen>=0)); then + ble/syntax/completion-context/.add command "$wbeg" + if [[ ${text:wbeg:index-wbeg} =~ $rex_param ]]; then + ble/syntax/completion-context/.add variable:= "$wbeg" + fi + fi + ble/syntax/completion-context/.check/parameter-expansion +} +_ble_syntax_bash_complete_check_prefix[_ble_ctx_ARGI]='inside-argument argument' +_ble_syntax_bash_complete_check_prefix[_ble_ctx_ARGQ]='inside-argument argument' +_ble_syntax_bash_complete_check_prefix[_ble_ctx_FARGI1]='inside-argument variable:w' +_ble_syntax_bash_complete_check_prefix[_ble_ctx_FARGI3]='inside-argument argument' +_ble_syntax_bash_complete_check_prefix[_ble_ctx_FARGQ3]='inside-argument argument' +_ble_syntax_bash_complete_check_prefix[_ble_ctx_CARGI1]='inside-argument argument' +_ble_syntax_bash_complete_check_prefix[_ble_ctx_CARGQ1]='inside-argument argument' +_ble_syntax_bash_complete_check_prefix[_ble_ctx_CPATI]='inside-argument argument' +_ble_syntax_bash_complete_check_prefix[_ble_ctx_CPATQ]='inside-argument argument' +_ble_syntax_bash_complete_check_prefix[_ble_ctx_COARGI]='inside-argument variable command' +_ble_syntax_bash_complete_check_prefix[_ble_ctx_VALI]='inside-argument sabbrev file' +_ble_syntax_bash_complete_check_prefix[_ble_ctx_VALQ]='inside-argument sabbrev file' +_ble_syntax_bash_complete_check_prefix[_ble_ctx_CONDI]='inside-argument sabbrev file option' +_ble_syntax_bash_complete_check_prefix[_ble_ctx_CONDQ]='inside-argument sabbrev file' +_ble_syntax_bash_complete_check_prefix[_ble_ctx_ARGVI]='inside-argument sabbrev variable:=' +_ble_syntax_bash_complete_check_prefix[_ble_ctx_ARGEI]='inside-argument command:D variable:= file' +function ble/syntax/completion-context/.check-prefix/ctx:inside-argument { + if ((wlen>=0)); then + local source + for source; do + ble/syntax/completion-context/.add "$source" "$wbeg" + if [[ $source != argument ]]; then + local sub=${text:wbeg:index-wbeg} + if [[ $sub == *[=:]* ]]; then + sub=${sub##*[=:]} + ble/syntax/completion-context/.add "$source" $((index-${#sub})) + fi + fi + done + fi + ble/syntax/completion-context/.check/parameter-expansion +} +_ble_syntax_bash_complete_check_prefix[_ble_ctx_CMDX]=next-command +_ble_syntax_bash_complete_check_prefix[_ble_ctx_CMDX1]=next-command +_ble_syntax_bash_complete_check_prefix[_ble_ctx_CMDXT]=next-command +_ble_syntax_bash_complete_check_prefix[_ble_ctx_CMDXV]=next-command +function ble/syntax/completion-context/.check-prefix/.test-redirection { + local word=$1 + [[ $word =~ ^$_ble_syntax_bash_RexRedirect$ ]] || return 1 + ((ctx==_ble_ctx_CMDXC||ctx==_ble_ctx_CMDXD||ctx==_ble_ctx_CMDXD0||ctx==_ble_ctx_FARGX3)) && return 0 + local rematch3=${BASH_REMATCH[3]} + case $rematch3 in + ('>&') + ble/syntax/completion-context/.add fd "$index" + ble/syntax/completion-context/.add file:no-fd "$index" ;; + (*'&') + ble/syntax/completion-context/.add fd "$index" ;; + ('<<'|'<<-') + ble/syntax/completion-context/.add wordlist:EOF:END:HERE "$index" ;; + ('<<<'|*) + ble/syntax/completion-context/.add file "$index" ;; + esac + return 0 +} +function ble/syntax/completion-context/.check-prefix/ctx:next-command { + local word=${text:istat:index-istat} + if ble/syntax:bash/simple-word/is-simple-or-open-simple "$word"; then + ble/syntax/completion-context/.add command "$istat" + if local rex='^[a-zA-Z_][a-zA-Z_0-9]*(\+?=)?$' && [[ $word =~ $rex ]]; then + if [[ $word == *= ]]; then + if ((_ble_bash>=30100)) || [[ $word != *+= ]]; then + ble/syntax/completion-context/.add argument "$index" + fi + else + ble/syntax/completion-context/.add variable:= "$istat" + fi + fi + elif ble/syntax/completion-context/.check-prefix/.test-redirection; then + true + elif [[ $word =~ ^$_ble_syntax_bash_RexSpaces$ ]]; then + shopt -q no_empty_cmd_completion || + ble/syntax/completion-context/.add command "$index" + fi + ble/syntax/completion-context/.check/parameter-expansion +} +_ble_syntax_bash_complete_check_prefix[_ble_ctx_ARGX]=next-argument +_ble_syntax_bash_complete_check_prefix[_ble_ctx_CARGX1]=next-argument +_ble_syntax_bash_complete_check_prefix[_ble_ctx_CPATX]=next-argument +_ble_syntax_bash_complete_check_prefix[_ble_ctx_FARGX3]=next-argument +_ble_syntax_bash_complete_check_prefix[_ble_ctx_COARGX]=next-argument +_ble_syntax_bash_complete_check_prefix[_ble_ctx_ARGVX]=next-argument +_ble_syntax_bash_complete_check_prefix[_ble_ctx_ARGEX]=next-argument +_ble_syntax_bash_complete_check_prefix[_ble_ctx_VALX]=next-argument +_ble_syntax_bash_complete_check_prefix[_ble_ctx_CONDX]=next-argument +_ble_syntax_bash_complete_check_prefix[_ble_ctx_RDRS]=next-argument +function ble/syntax/completion-context/.check-prefix/ctx:next-argument { + local source + if ((ctx==_ble_ctx_ARGX||ctx==_ble_ctx_CARGX1||ctx==_ble_ctx_FARGX3)); then + source=(argument) + elif ((ctx==_ble_ctx_COARGX)); then + source=(command variable) + elif ((ctx==_ble_ctx_ARGVX)); then + source=(sabbrev variable:= option) + elif ((ctx==_ble_ctx_ARGEX)); then + source=(command:D variable:= file) + elif ((ctx==_ble_ctx_CONDX)); then + source=(sabbrev file option) + else + source=(sabbrev file) + fi + local word=${text:istat:index-istat} + if ble/syntax:bash/simple-word/is-simple-or-open-simple "$word"; then + local src + for src in "${source[@]}"; do + ble/syntax/completion-context/.add "$src" "$istat" + done + if [[ ${source[0]} != argument ]]; then + local rex="^([^='\"\$\\{}]|\\.)*=" + if [[ $word =~ $rex ]]; then + word=${word:${#BASH_REMATCH}} + ble/syntax/completion-context/.add rhs $((index-${#word})) + fi + fi + elif ble/syntax/completion-context/.check-prefix/.test-redirection "$word"; then + true + elif [[ $word =~ ^$_ble_syntax_bash_RexSpaces$ ]]; then + local src + for src in "${source[@]}"; do + ble/syntax/completion-context/.add "$src" "$index" + done + fi + ble/syntax/completion-context/.check/parameter-expansion +} +_ble_syntax_bash_complete_check_prefix[_ble_ctx_CMDXC]=next-compound +function ble/syntax/completion-context/.check-prefix/ctx:next-compound { + local rex word=${text:istat:index-istat} + if [[ ${text:istat:index-istat} =~ $rex_param ]]; then + ble/syntax/completion-context/.add wordlist:-r:'for:select:case:if:while:until' "$istat" + elif rex='^[[({]+$'; [[ $word =~ $rex ]]; then + ble/syntax/completion-context/.add wordlist:-r:'(:{:((:[[' "$istat" + fi +} +_ble_syntax_bash_complete_check_prefix[_ble_ctx_FARGX1]="next-identifier variable:w" # _ble_ctx_FARGX1 → (( でなければ 変数名 +_ble_syntax_bash_complete_check_prefix[_ble_ctx_SARGX1]="next-identifier variable:w" +function ble/syntax/completion-context/.check-prefix/ctx:next-identifier { + local source=$1 word=${text:istat:index-istat} + if [[ $word =~ $rex_param ]]; then + ble/syntax/completion-context/.add "$source" "$istat" + elif [[ $word =~ ^$_ble_syntax_bash_RexSpaces$ ]]; then + ble/syntax/completion-context/.add "$source" "$index" + else + ble/syntax/completion-context/.add none "$istat" + fi +} +_ble_syntax_bash_complete_check_prefix[_ble_ctx_ARGX0]="next-word sabbrev" +_ble_syntax_bash_complete_check_prefix[_ble_ctx_CPATX0]="next-word sabbrev" +_ble_syntax_bash_complete_check_prefix[_ble_ctx_CMDXD0]="next-word wordlist:-rs:';:{:do'" +_ble_syntax_bash_complete_check_prefix[_ble_ctx_CMDXD]="next-word wordlist:-rs:'{:do'" +_ble_syntax_bash_complete_check_prefix[_ble_ctx_CMDXE]="next-word wordlist:-rs:'}:fi:done:esac:then:elif:else:do'" +_ble_syntax_bash_complete_check_prefix[_ble_ctx_CARGX2]="next-word wordlist:-rs:'in'" +_ble_syntax_bash_complete_check_prefix[_ble_ctx_CARGI2]="next-word wordlist:-rs:'in'" +_ble_syntax_bash_complete_check_prefix[_ble_ctx_FARGX2]="next-word wordlist:-rs:'in:do'" +_ble_syntax_bash_complete_check_prefix[_ble_ctx_FARGI2]="next-word wordlist:-rs:'in:do'" +function ble/syntax/completion-context/.check-prefix/ctx:next-word { + local source=$1 word=${text:istat:index-istat} rex=$'^[^ \t]*$' + if [[ $word =~ ^$_ble_syntax_bash_RexSpaces$ ]]; then + ble/syntax/completion-context/.add "$source" "$index" + else + ble/syntax/completion-context/.add "$source" "$istat" + fi +} +_ble_syntax_bash_complete_check_prefix[_ble_ctx_TARGX1]=time-argument +_ble_syntax_bash_complete_check_prefix[_ble_ctx_TARGI1]=time-argument +_ble_syntax_bash_complete_check_prefix[_ble_ctx_TARGX2]=time-argument +_ble_syntax_bash_complete_check_prefix[_ble_ctx_TARGI2]=time-argument +function ble/syntax/completion-context/.check-prefix/ctx:time-argument { + ble/syntax/completion-context/.check/parameter-expansion + ble/syntax/completion-context/.add command "$istat" + if ((ctx==_ble_ctx_TARGX1)); then + local rex='^-p?$' words='-p' + ((_ble_bash>=50100)) && + rex='^-[-p]?$' words='-p':'--' + [[ ${text:istat:index-istat} =~ $rex ]] && + ble/syntax/completion-context/.add wordlist:--:"$words" "$istat" + elif ((ctx==_ble_ctx_TARGX2)); then + local rex='^--?$' + [[ ${text:istat:index-istat} =~ $rex ]] && + ble/syntax/completion-context/.add wordlist:--:'--' "$istat" + fi +} +_ble_syntax_bash_complete_check_prefix[_ble_ctx_QUOT]=quote +function ble/syntax/completion-context/.check-prefix/ctx:quote { + ble/syntax/completion-context/.check/parameter-expansion + ble/syntax/completion-context/.check-prefix/ctx:quote/.check-container-word +} +function ble/syntax/completion-context/.check-prefix/ctx:quote/.check-container-word { + local nlen=${stat[3]}; ((nlen>=0)) || return 1 + local inest=$((nlen<0?nlen:istat-nlen)) + local nest; ble/string#split-words nest "${_ble_syntax_nest[inest]}" + [[ ${nest[0]} ]] || return 1 + local wlen2=${nest[1]}; ((wlen2>=0)) || return 1 + local wbeg2=$((wlen2<0?wlen2:inest-wlen2)) + if ble/syntax:bash/simple-word/is-simple-or-open-simple "${text:wbeg2:index-wbeg2}"; then + local wt=${nest[2]} + [[ ${_ble_syntax_bash_command_EndWtype[wt]} ]] && + wt=${_ble_syntax_bash_command_EndWtype[wt]} + if ((wt==_ble_ctx_CMDI)); then + ble/syntax/completion-context/.add command "$wbeg2" + elif ((wt==_ble_ctx_ARGI||wt==_ble_ctx_ARGVI||wt==_ble_ctx_ARGEI||wt==_ble_ctx_FARGI2||wt==_ble_ctx_CARGI2)); then + ble/syntax/completion-context/.add argument "$wbeg2" + elif ((wt==_ble_ctx_CPATI)); then # case pattern の内部 + return + fi + fi +} +_ble_syntax_bash_complete_check_prefix[_ble_ctx_RDRF]=redirection +_ble_syntax_bash_complete_check_prefix[_ble_ctx_RDRD2]=redirection +_ble_syntax_bash_complete_check_prefix[_ble_ctx_RDRD]=redirection +function ble/syntax/completion-context/.check-prefix/ctx:redirection { + ble/syntax/completion-context/.check/parameter-expansion + local p=$((wlen>=0?wbeg:istat)) + if ble/syntax:bash/simple-word/is-simple-or-open-simple "${text:p:index-p}"; then + if ((ctx==_ble_ctx_RDRF)); then + ble/syntax/completion-context/.add file "$p" + elif ((ctx==_ble_ctx_RDRD)); then + ble/syntax/completion-context/.add fd "$p" + elif ((ctx==_ble_ctx_RDRD2)); then + ble/syntax/completion-context/.add fd "$p" + ble/syntax/completion-context/.add file:no-fd "$p" + fi + fi +} +_ble_syntax_bash_complete_check_prefix[_ble_ctx_RDRH]=here +_ble_syntax_bash_complete_check_prefix[_ble_ctx_RDRI]=here +function ble/syntax/completion-context/.check-prefix/ctx:here { + local p=$((wlen>=0?wbeg:istat)) + ble/syntax/completion-context/.add wordlist:EOF:END:HERE "$p" +} +_ble_syntax_bash_complete_check_prefix[_ble_ctx_VRHS]=rhs +_ble_syntax_bash_complete_check_prefix[_ble_ctx_ARGVR]=rhs +_ble_syntax_bash_complete_check_prefix[_ble_ctx_ARGER]=rhs +_ble_syntax_bash_complete_check_prefix[_ble_ctx_VALR]=rhs +function ble/syntax/completion-context/.check-prefix/ctx:rhs { + ble/syntax/completion-context/.check/parameter-expansion + if ((wlen>=0)); then + local p=$wbeg + local rex='^[a-zA-Z0-9_]+(\+?=|\[)' + ((ctx==_ble_ctx_VALR)) && rex='^(\[)' + if [[ ${text:p:index-p} =~ $rex ]]; then + if [[ ${BASH_REMATCH[1]} == '[' ]]; then + local p1=$((wbeg+${#BASH_REMATCH}-1)) + if local ret; ble/syntax:bash/find-end-of-array-index "$p1" "$index"; then + local p2=$ret + case ${_ble_syntax_text:p2:index-p2} in + (']='*) ((p=p2+2)) ;; + (']+='*) ((p=p2+3)) ;; + (']+') + ble/syntax/completion-context/.add wordlist:-rW:'+=' $((p2+1)) + p= ;; + esac + fi + else + ((p+=${#BASH_REMATCH})) + fi + fi + else + local p=$istat + fi + if [[ $p ]] && ble/syntax:bash/simple-word/is-simple-or-open-simple "${text:p:index-p}"; then + ble/syntax/completion-context/.add rhs "$p" + fi +} +_ble_syntax_bash_complete_check_prefix[_ble_ctx_PARAM]=param +function ble/syntax/completion-context/.check-prefix/ctx:param { + local tail=${text:istat:index-istat} + if [[ $tail == : ]]; then + return 0 + elif [[ $tail == '}'* ]]; then + local nlen=${stat[3]} + local inest=$((nlen<0?nlen:istat-nlen)) + ((0<=inest&&inest<istat)) && + ble/syntax/completion-context/.check-prefix "$inest" + return "$?" + else + return 1 + fi +} +_ble_syntax_bash_complete_check_prefix[_ble_ctx_EXPR]=expr +function ble/syntax/completion-context/.check-prefix/ctx:expr { + local tail=${text:istat:index-istat} rex='[a-zA-Z_]+$' + if [[ $tail =~ $rex ]]; then + local p=$((index-${#BASH_REMATCH})) + ble/syntax/completion-context/.add variable:a "$p" + return 0 + elif [[ $tail == ']'* ]]; then + local inest=... ntype + local nlen=${stat[3]}; ((nlen>=0)) || return 1 + local inest=$((istat-nlen)) + ble/syntax/parse/nest-type # ([in] inest; [out] ntype) + if [[ $ntype == [ad]'[' ]]; then + if [[ $tail == ']' ]]; then + ble/syntax/completion-context/.add wordlist:-rW:'=' $((istat+1)) + elif ((_ble_bash>=30100)) && [[ $tail == ']+' ]]; then + ble/syntax/completion-context/.add wordlist:-rW:'+=' $((istat+1)) + elif [[ $tail == ']=' || _ble_bash -ge 30100 && $tail == ']+=' ]]; then + ble/syntax/completion-context/.add rhs "$index" + fi + fi + fi +} +_ble_syntax_bash_complete_check_prefix[_ble_ctx_BRACE1]=brace +_ble_syntax_bash_complete_check_prefix[_ble_ctx_BRACE2]=brace +function ble/syntax/completion-context/.check-prefix/ctx:brace { + local ctx1=$ctx istat1=$istat nlen1=${stat[3]} + ((nlen1>=0)) || return 1 + local inest1=$((istat1-nlen1)) + while :; do + local nest=${_ble_syntax_nest[inest1]} + [[ $nest ]] || return 1 + ble/string#split-words nest "$nest" + ctx1=${nest[0]} + ((ctx1==_ble_ctx_BRACE1||ctx1==_ble_ctx_BRACE2)) || break + inest1=${nest[3]} + ((inest1>=0)) || return 1 + done + for ((istat1=inest1;1;istat1--)); do + ((istat1>=0)) || return 1 + [[ ${_ble_syntax_stat[istat1]} ]] && break + done + local stat1 + ble/string#split-words stat1 "${_ble_syntax_stat[istat1]}" + local wlen=${stat1[1]} + local wbeg=$((wlen>=0?istat1-wlen:istat1)) + ble/syntax/completion-context/.check/parameter-expansion + ble/syntax/completion-context/.add argument "$wbeg" +} +function ble/syntax/completion-context/.search-last-istat { + local index=$1 istat + for ((istat=index;istat>=0;istat--)); do + if [[ ${_ble_syntax_stat[istat]} ]]; then + ret=$istat + return 0 + fi + done + ret= + return 1 +} +function ble/syntax/completion-context/.check-prefix { + local rex_param='^[a-zA-Z_][a-zA-Z_0-9]*$' + local from=${1:-$((index-1))} + local ret + ble/syntax/completion-context/.search-last-istat "$from" || return 1 + local istat=$ret stat + ble/string#split-words stat "${_ble_syntax_stat[istat]}" + [[ ${stat[0]} ]] || return 1 + local ctx=${stat[0]} wlen=${stat[1]} + local wbeg=$((wlen<0?wlen:istat-wlen)) + local name=${_ble_syntax_bash_complete_check_prefix[ctx]} + if [[ $name ]]; then + builtin eval "ble/syntax/completion-context/.check-prefix/ctx:$name" + fi +} +function ble/syntax/completion-context/.check-here { + ((${#sources[*]})) && return 0 + local -a stat + ble/string#split-words stat "${_ble_syntax_stat[index]}" + if [[ ${stat[0]} ]]; then + local ctx=${stat[0]} + if ((ctx==_ble_ctx_CMDX||ctx==_ble_ctx_CMDXV||ctx==_ble_ctx_CMDX1||ctx==_ble_ctx_CMDXT)); then + if ! shopt -q no_empty_cmd_completion; then + ble/syntax/completion-context/.add command "$index" + ble/syntax/completion-context/.add variable:= "$index" + fi + elif ((ctx==_ble_ctx_CMDXC)); then + ble/syntax/completion-context/.add wordlist:-rs:'(:{:((:[[:for:select:case:if:while:until' "$index" + elif ((ctx==_ble_ctx_CMDXE)); then + ble/syntax/completion-context/.add wordlist:-rs:'}:fi:done:esac:then:elif:else:do' "$index" + elif ((ctx==_ble_ctx_CMDXD0)); then + ble/syntax/completion-context/.add wordlist:-rs:';:{:do' "$index" + elif ((ctx==_ble_ctx_CMDXD)); then + ble/syntax/completion-context/.add wordlist:-rs:'{:do' "$index" + elif ((ctx==_ble_ctx_ARGX0||ctx==_ble_ctx_CPATX0)); then + ble/syntax/completion-context/.add sabbrev "$index" + elif ((ctx==_ble_ctx_ARGX||ctx==_ble_ctx_CARGX1||ctx==_ble_ctx_FARGX3)); then + ble/syntax/completion-context/.add argument "$index" + elif ((ctx==_ble_ctx_FARGX1||ctx==_ble_ctx_SARGX1)); then + ble/syntax/completion-context/.add variable:w "$index" + ble/syntax/completion-context/.add sabbrev "$index" + elif ((ctx==_ble_ctx_ARGVX)); then + ble/syntax/completion-context/.add variable:= "$index" + ble/syntax/completion-context/.add option "$index" + ble/syntax/completion-context/.add sabbrev "$index" + elif ((ctx==_ble_ctx_ARGEX)); then + ble/syntax/completion-context/.add variable:= "$index" + ble/syntax/completion-context/.add command:D "$index" + ble/syntax/completion-context/.add file "$index" + elif ((ctx==_ble_ctx_CARGX2)); then + ble/syntax/completion-context/.add wordlist:-rs:'in' "$index" + elif ((ctx==_ble_ctx_FARGX2)); then + ble/syntax/completion-context/.add wordlist:-rs:'in:do' "$index" + elif ((ctx==_ble_ctx_TARGX1)); then + local words='-p' + ((_ble_bash>=50100)) && words='-p':'--' + ble/syntax/completion-context/.add command "$index" + ble/syntax/completion-context/.add wordlist:--:"$words" "$index" + elif ((ctx==_ble_ctx_TARGX2)); then + ble/syntax/completion-context/.add command "$index" + ble/syntax/completion-context/.add wordlist:--:'--' "$index" + elif ((ctx==_ble_ctx_COARGX)); then + ble/syntax/completion-context/.add variable:w "$index" + ble/syntax/completion-context/.add command "$index" + elif ((ctx==_ble_ctx_CONDX)); then + ble/syntax/completion-context/.add sabbrev "$index" + ble/syntax/completion-context/.add option "$index" + ble/syntax/completion-context/.add file "$index" + elif ((ctx==_ble_ctx_CPATI||ctx==_ble_ctx_RDRF||ctx==_ble_ctx_RDRS)); then + ble/syntax/completion-context/.add file "$index" + elif ((ctx==_ble_ctx_RDRD)); then + ble/syntax/completion-context/.add fd "$index" + elif ((ctx==_ble_ctx_RDRD2)); then + ble/syntax/completion-context/.add fd "$index" + ble/syntax/completion-context/.add file:no-fd "$index" + elif ((ctx==_ble_ctx_RDRH||ctx==_ble_ctx_RDRI)); then + ble/syntax/completion-context/.add wordlist:EOF:END:HERE "$index" + elif ((ctx==_ble_ctx_VRHS||ctx==_ble_ctx_ARGVR||ctx==_ble_ctx_ARGER||ctx==_ble_ctx_VALR)); then + ble/syntax/completion-context/.add rhs "$index" + fi + fi +} +function ble/syntax/completion-context/generate { + local text=$1 index=$2 + sources=() + ((index<0&&(index=0))) + ble/syntax/completion-context/.check-prefix + ble/syntax/completion-context/.check-here +} +function ble/syntax:bash/extract-command/.register-word { + local wtxt=${_ble_syntax_text:wbegin:wlen} + if [[ ! $comp_cword ]] && ((wbegin<=EC_pos)); then + if ((EC_pos<=wbegin+wlen)); then + comp_cword=${#comp_words[@]} + comp_point=$((${#comp_line}+wbegin+wlen-EC_pos)) + comp_line="$wtxt$comp_line" + ble/array#push comp_words "$wtxt" + else + comp_cword=${#comp_words[@]} + comp_point=${#comp_line} + comp_line="$wtxt $comp_line" + ble/array#push comp_words "" "$wtxt" + fi + else + comp_line="$wtxt$comp_line" + ble/array#push comp_words "$wtxt" + fi + [[ $EC_opts == *:treeinfo:* ]] && + ble/array#push tree_words "$TE_i:$TE_nofs" +} +function ble/syntax:bash/extract-command/.construct-proc { + if [[ $wtype =~ ^[0-9]+$ ]]; then + if ((wtype==_ble_ctx_CMDI)); then + if ((EC_pos<wbegin)); then + comp_line= comp_point= comp_cword= comp_words=() + else + ble/syntax:bash/extract-command/.register-word + ble/syntax/tree-enumerate-break + EC_found=1 + return 0 + fi + elif ((wtype==_ble_ctx_ARGI||wtype==_ble_ctx_ARGVI||wtype==_ble_ctx_ARGEI||wtype==_ble_attr_VAR)); then + ble/syntax:bash/extract-command/.register-word + comp_line=" $comp_line" + fi + fi +} +function ble/syntax:bash/extract-command/.construct { + comp_line= comp_point= comp_cword= comp_words=() + if [[ $1 == nested ]]; then + ble/syntax/tree-enumerate-children \ + ble/syntax:bash/extract-command/.construct-proc + else + ble/syntax/tree-enumerate \ + ble/syntax:bash/extract-command/.construct-proc + fi + ble/array#reverse comp_words + ((comp_cword=${#comp_words[@]}-1-comp_cword, + comp_point=${#comp_line}-comp_point)) + [[ $EC_opts == *:treeinfo:* ]] && + ble/array#reverse tree_words +} +function ble/syntax:bash/extract-command/.scan { + ((EC_pos<wbegin)) && return 0 + if ((wbegin+wlen<EC_pos)); then + ble/syntax/tree-enumerate-break + else + local EC_has_word= + ble/syntax/tree-enumerate-children \ + ble/syntax:bash/extract-command/.scan + local has_word=$EC_has_word + ble/util/unlocal EC_has_word + if [[ $has_word && ! $EC_found ]]; then + ble/syntax:bash/extract-command/.construct nested + ble/syntax/tree-enumerate-break + fi + fi + if [[ $wtype =~ ^[0-9]+$ && ! $EC_has_word ]]; then + EC_has_word=$wtype + return 0 + fi +} +function ble/syntax:bash/extract-command { + local EC_pos=$1 EC_opts=:$2: + local EC_found= + local EC_has_word= + ble/syntax/tree-enumerate \ + ble/syntax:bash/extract-command/.scan + if [[ ! $EC_found && $EC_has_word ]]; then + ble/syntax:bash/extract-command/.construct + fi + [[ $EC_found ]] +} +function ble/syntax/tree#previous-sibling { + local i0=${1%%:*} nofs0=0 opts=:$2: + [[ $1 == *:* ]] && nofs0=${1#*:} + local node + ble/string#split-words node "${_ble_syntax_tree[i0-1]}" + ble-assert '((${#node[@]}>nofs0))' "Broken AST: tree-node info missing at $((i0-1))[$nofs0]" || return 1 + local tplen=${node[nofs0+3]} + ((tplen>=0)) || return 1 + local i=$((i0-tplen)) nofs=0 + ret=$i:$nofs + if [[ $opts == *:wvars:* ]]; then + ble/string#split-words node "${_ble_syntax_tree[i-1]}" + ble-assert '((${#node[@]}>nofs))' "Broken AST: tree-node info missing at $((i-1))[$nofs]" || return 1 + wtype=${node[nofs]} + wlen=${node[nofs+1]} + ((wbeg=i-wlen,wend=i)) + wattr=${node[nofs+4]} + fi + return 0 +} +function ble/syntax/tree#next-sibling { + local i0=${1%%:*} nofs0=0 opts=:$2: + [[ $1 == *:* ]] && nofs0=${1#*:} + ((nofs0)) && return 1 + local iN=${#_ble_syntax_text} i nofs node + for ((i=i0+1;i<=iN;i++)); do + [[ ${_ble_syntax_tree[i-1]} ]] || continue + ble/string#split-words node "${_ble_syntax_tree[i-1]}" + nofs=${#node[@]} + while (((nofs-=_ble_syntax_TREE_WIDTH)>=0)); do + if ((i0==i-node[nofs+2])); then + return 1 + elif ((i0==i-node[nofs+3])); then + ret=$i:$nofs + if [[ $opts == *:wvars:* ]]; then + wtype=${node[nofs]} + wlen=${node[nofs+1]} + ((wbeg=i-wlen,wend=i)) + wattr=${node[nofs+4]} + fi + return 0 + fi + done + done + return 1 +} +function ble/syntax:bash/extract-command-by-noderef { + local i=${1%%:*} nofs=0 opts=:$2: + [[ $1 == *:* ]] && nofs=${1#*:} + comp_words=() + tree_words=() + comp_line= + comp_cword=0 + comp_point=0 + local ExprIsArgument='wtype==_ble_ctx_ARGI||wtype==_ble_ctx_ARGVI||wtype==_ble_ctx_ARGEI||wtype==_ble_attr_VAR' + local ret node wtype wlen wbeg wend wattr + ble/string#split-words node "${_ble_syntax_tree[i-1]}" + wtype=${node[nofs]} wlen=${node[nofs+1]} + [[ ! ${wtype//[0-9]} ]] && ((wtype==_ble_ctx_CMDI||ExprIsArgument)) || return 1 + ble/array#push comp_words "${_ble_syntax_text:i-wlen:wlen}" + [[ $opts == *:treeinfo:* ]] && + ble/array#push tree_words "$i:$nofs" + ret=$i:$nofs + while + { [[ ${wtype//[0-9]} ]] || ((wtype!=_ble_ctx_CMDI)); } && + ble/syntax/tree#previous-sibling "$ret" wvars + do + [[ ! ${wtype//[0-9]} ]] || continue + if ((wtype==_ble_ctx_CMDI||ExprIsArgument)); then + ble/array#push comp_words "${_ble_syntax_text:wbeg:wlen}" + [[ $opts == *:treeinfo:* ]] && + ble/array#push tree_words "$ret" + fi + done + ble/array#reverse comp_words + [[ $opts == *:treeinfo:* ]] && + ble/array#reverse tree_words + ((comp_cword=${#comp_words[@]}-1)) + ret=$i:$nofs + while ble/syntax/tree#next-sibling "$ret" wvars; do + [[ ! ${wtype//[0-9]} ]] || continue + ((wtype==_ble_ctx_CMDI)) && break + if ((ExprIsArgument)); then + ble/array#push comp_words "${_ble_syntax_text:wbeg:wlen}" + [[ $opts == *:treeinfo:* ]] && + ble/array#push tree_words "$ret" + fi + done + local IFS=$_ble_term_IFS + comp_line="${comp_words[*]}" + local tmp="${comp_words[*]::comp_cword+1}" + comp_point=${#tmp} +} +_ble_syntax_attr2iface=() +function ble/syntax/attr2iface/color_defface.onload { + function ble/syntax/attr2iface/.define { + ((_ble_syntax_attr2iface[$1]=_ble_faces__$2)) + } + ble/syntax/attr2iface/.define _ble_ctx_ARGX syntax_default + ble/syntax/attr2iface/.define _ble_ctx_ARGX0 syntax_default + ble/syntax/attr2iface/.define _ble_ctx_ARGI syntax_default + ble/syntax/attr2iface/.define _ble_ctx_ARGQ syntax_default + ble/syntax/attr2iface/.define _ble_ctx_ARGVX syntax_default + ble/syntax/attr2iface/.define _ble_ctx_ARGVI syntax_default + ble/syntax/attr2iface/.define _ble_ctx_ARGVR syntax_default + ble/syntax/attr2iface/.define _ble_ctx_ARGEX syntax_default + ble/syntax/attr2iface/.define _ble_ctx_ARGEI syntax_default + ble/syntax/attr2iface/.define _ble_ctx_ARGER syntax_default + ble/syntax/attr2iface/.define _ble_ctx_CMDX syntax_default + ble/syntax/attr2iface/.define _ble_ctx_CMDX1 syntax_default + ble/syntax/attr2iface/.define _ble_ctx_CMDXT syntax_default + ble/syntax/attr2iface/.define _ble_ctx_CMDXC syntax_default + ble/syntax/attr2iface/.define _ble_ctx_CMDXE syntax_default + ble/syntax/attr2iface/.define _ble_ctx_CMDXD syntax_default + ble/syntax/attr2iface/.define _ble_ctx_CMDXD0 syntax_default + ble/syntax/attr2iface/.define _ble_ctx_CMDXV syntax_default + ble/syntax/attr2iface/.define _ble_ctx_CMDI syntax_command + ble/syntax/attr2iface/.define _ble_ctx_VRHS syntax_default + ble/syntax/attr2iface/.define _ble_ctx_QUOT syntax_quoted + ble/syntax/attr2iface/.define _ble_ctx_EXPR syntax_expr + ble/syntax/attr2iface/.define _ble_attr_ERR syntax_error + ble/syntax/attr2iface/.define _ble_attr_VAR syntax_varname + ble/syntax/attr2iface/.define _ble_attr_QDEL syntax_quotation + ble/syntax/attr2iface/.define _ble_attr_QESC syntax_escape + ble/syntax/attr2iface/.define _ble_attr_DEF syntax_default + ble/syntax/attr2iface/.define _ble_attr_DEL syntax_delimiter + ble/syntax/attr2iface/.define _ble_ctx_PARAM syntax_param_expansion + ble/syntax/attr2iface/.define _ble_ctx_PWORD syntax_default + ble/syntax/attr2iface/.define _ble_ctx_PWORDE syntax_error + ble/syntax/attr2iface/.define _ble_ctx_PWORDR syntax_default + ble/syntax/attr2iface/.define _ble_attr_HISTX syntax_history_expansion + ble/syntax/attr2iface/.define _ble_attr_FUNCDEF syntax_function_name + ble/syntax/attr2iface/.define _ble_ctx_VALX syntax_default + ble/syntax/attr2iface/.define _ble_ctx_VALI syntax_default + ble/syntax/attr2iface/.define _ble_ctx_VALR syntax_default + ble/syntax/attr2iface/.define _ble_ctx_VALQ syntax_default + ble/syntax/attr2iface/.define _ble_ctx_CONDX syntax_default + ble/syntax/attr2iface/.define _ble_ctx_CONDI syntax_default + ble/syntax/attr2iface/.define _ble_ctx_CONDQ syntax_default + ble/syntax/attr2iface/.define _ble_attr_COMMENT syntax_comment + ble/syntax/attr2iface/.define _ble_ctx_CASE syntax_default + ble/syntax/attr2iface/.define _ble_ctx_PATN syntax_default + ble/syntax/attr2iface/.define _ble_attr_GLOB syntax_glob + ble/syntax/attr2iface/.define _ble_ctx_BRAX syntax_default + ble/syntax/attr2iface/.define _ble_attr_BRACE syntax_brace + ble/syntax/attr2iface/.define _ble_ctx_BRACE1 syntax_default + ble/syntax/attr2iface/.define _ble_ctx_BRACE2 syntax_default + ble/syntax/attr2iface/.define _ble_attr_TILDE syntax_tilde + ble/syntax/attr2iface/.define _ble_ctx_SARGX1 syntax_default + ble/syntax/attr2iface/.define _ble_ctx_FARGX1 syntax_default + ble/syntax/attr2iface/.define _ble_ctx_FARGX2 syntax_default + ble/syntax/attr2iface/.define _ble_ctx_FARGX3 syntax_default + ble/syntax/attr2iface/.define _ble_ctx_FARGI1 syntax_varname + ble/syntax/attr2iface/.define _ble_ctx_FARGI2 command_keyword + ble/syntax/attr2iface/.define _ble_ctx_FARGI3 syntax_default + ble/syntax/attr2iface/.define _ble_ctx_FARGQ3 syntax_default + ble/syntax/attr2iface/.define _ble_ctx_CARGX1 syntax_default + ble/syntax/attr2iface/.define _ble_ctx_CARGX2 syntax_default + ble/syntax/attr2iface/.define _ble_ctx_CARGI1 syntax_default + ble/syntax/attr2iface/.define _ble_ctx_CARGQ1 syntax_default + ble/syntax/attr2iface/.define _ble_ctx_CARGI2 command_keyword + ble/syntax/attr2iface/.define _ble_ctx_CPATX syntax_default + ble/syntax/attr2iface/.define _ble_ctx_CPATI syntax_default + ble/syntax/attr2iface/.define _ble_ctx_CPATQ syntax_default + ble/syntax/attr2iface/.define _ble_ctx_CPATX0 syntax_default + ble/syntax/attr2iface/.define _ble_ctx_TARGX1 syntax_default + ble/syntax/attr2iface/.define _ble_ctx_TARGX2 syntax_default + ble/syntax/attr2iface/.define _ble_ctx_TARGI1 syntax_default + ble/syntax/attr2iface/.define _ble_ctx_TARGI2 syntax_default + ble/syntax/attr2iface/.define _ble_ctx_COARGX syntax_default + ble/syntax/attr2iface/.define _ble_ctx_COARGI syntax_command + ble/syntax/attr2iface/.define _ble_ctx_RDRF syntax_default + ble/syntax/attr2iface/.define _ble_ctx_RDRD syntax_default + ble/syntax/attr2iface/.define _ble_ctx_RDRD2 syntax_default + ble/syntax/attr2iface/.define _ble_ctx_RDRS syntax_default + ble/syntax/attr2iface/.define _ble_ctx_RDRH syntax_document_begin + ble/syntax/attr2iface/.define _ble_ctx_RDRI syntax_document_begin + ble/syntax/attr2iface/.define _ble_ctx_HERE0 syntax_document + ble/syntax/attr2iface/.define _ble_ctx_HERE1 syntax_document + ble/syntax/attr2iface/.define _ble_attr_CMD_BOLD command_builtin_dot + ble/syntax/attr2iface/.define _ble_attr_CMD_BUILTIN command_builtin + ble/syntax/attr2iface/.define _ble_attr_CMD_ALIAS command_alias + ble/syntax/attr2iface/.define _ble_attr_CMD_FUNCTION command_function + ble/syntax/attr2iface/.define _ble_attr_CMD_FILE command_file + ble/syntax/attr2iface/.define _ble_attr_CMD_JOBS command_jobs + ble/syntax/attr2iface/.define _ble_attr_CMD_DIR command_directory + ble/syntax/attr2iface/.define _ble_attr_KEYWORD command_keyword + ble/syntax/attr2iface/.define _ble_attr_KEYWORD_BEGIN command_keyword + ble/syntax/attr2iface/.define _ble_attr_KEYWORD_END command_keyword + ble/syntax/attr2iface/.define _ble_attr_KEYWORD_MID command_keyword + ble/syntax/attr2iface/.define _ble_attr_FILE_DIR filename_directory + ble/syntax/attr2iface/.define _ble_attr_FILE_STICKY filename_directory_sticky + ble/syntax/attr2iface/.define _ble_attr_FILE_LINK filename_link + ble/syntax/attr2iface/.define _ble_attr_FILE_ORPHAN filename_orphan + ble/syntax/attr2iface/.define _ble_attr_FILE_FILE filename_other + ble/syntax/attr2iface/.define _ble_attr_FILE_SETUID filename_setuid + ble/syntax/attr2iface/.define _ble_attr_FILE_SETGID filename_setgid + ble/syntax/attr2iface/.define _ble_attr_FILE_EXEC filename_executable + ble/syntax/attr2iface/.define _ble_attr_FILE_WARN filename_warning + ble/syntax/attr2iface/.define _ble_attr_FILE_FIFO filename_pipe + ble/syntax/attr2iface/.define _ble_attr_FILE_SOCK filename_socket + ble/syntax/attr2iface/.define _ble_attr_FILE_BLK filename_block + ble/syntax/attr2iface/.define _ble_attr_FILE_CHR filename_character + ble/syntax/attr2iface/.define _ble_attr_FILE_URL filename_url + ble/syntax/attr2iface/.define _ble_attr_VAR_UNSET varname_unset + ble/syntax/attr2iface/.define _ble_attr_VAR_EMPTY varname_empty + ble/syntax/attr2iface/.define _ble_attr_VAR_NUMBER varname_number + ble/syntax/attr2iface/.define _ble_attr_VAR_EXPR varname_expr + ble/syntax/attr2iface/.define _ble_attr_VAR_ARRAY varname_array + ble/syntax/attr2iface/.define _ble_attr_VAR_HASH varname_hash + ble/syntax/attr2iface/.define _ble_attr_VAR_READONLY varname_readonly + ble/syntax/attr2iface/.define _ble_attr_VAR_TRANSFORM varname_transform + ble/syntax/attr2iface/.define _ble_attr_VAR_EXPORT varname_export +} +blehook/eval-after-load color_defface ble/syntax/attr2iface/color_defface.onload +function ble/syntax/highlight/cmdtype1 { + type=$1 + local cmd=$2 + case "$type:$cmd" in + (builtin::|builtin:.) + ((type=_ble_attr_CMD_BOLD)) ;; + (builtin:*) + ((type=_ble_attr_CMD_BUILTIN)) ;; + (alias:*) + ((type=_ble_attr_CMD_ALIAS)) ;; + (function:*) + ((type=_ble_attr_CMD_FUNCTION)) ;; + (file:*) + ((type=_ble_attr_CMD_FILE)) ;; + (keyword:*) + ((type=_ble_attr_KEYWORD)) ;; + (*:%*) + ble/util/joblist.check + if jobs -- "$cmd" &>/dev/null; then + ((type=_ble_attr_CMD_JOBS)) + else + ((type=_ble_attr_ERR)) + fi ;; + (*) + if [[ -d $cmd ]] && shopt -q autocd &>/dev/null; then + ((type=_ble_attr_CMD_DIR)) + else + ((type=_ble_attr_ERR)) + fi ;; + esac +} +function ble/syntax/highlight/cmdtype/.jobs { local LC_ALL=C; jobs; } +ble/function#suppress-stderr ble/syntax/highlight/cmdtype/.jobs +function ble/syntax/highlight/cmdtype/.is-job-name { + ble/util/joblist.check + local value=$1 word=$2 + if [[ $value == '%'* ]] && jobs -- "$value" &>/dev/null; then + return 0 + fi + local quote=\'\"\\\` + if [[ ${auto_resume+set} && $word != *["$quote"]* ]]; then + if [[ $auto_resume == exact ]]; then + local jobs job ret + ble/util/assign-array jobs 'ble/syntax/highlight/cmdtype/.jobs' + for job in "${jobs[@]}"; do + ble/string#trim "${job#*' '}" + ble/string#trim "${ret#*' '}" + [[ $value == "$ret" ]] && return 0 + done + return 1 + elif [[ $auto_resume == substring ]]; then + jobs -- "%?$value" &>/dev/null; return "$?" + else + jobs -- "%$value" &>/dev/null; return "$?" + fi + fi + return 1 +} +function ble/syntax/highlight/cmdtype/.impl { + local cmd=$1 _0=$2 + local cmd_type; ble/util/type cmd_type "$cmd" + ble/syntax/highlight/cmdtype1 "$cmd_type" "$cmd" + if [[ $type == "$_ble_attr_CMD_ALIAS" && $cmd != "$_0" ]]; then + type=$( + builtin unalias "$cmd" + ble/util/type cmd_type "$cmd" + ble/syntax/highlight/cmdtype1 "$cmd_type" "$cmd" + printf %s "$type") + elif ble/syntax/highlight/cmdtype/.is-job-name "$cmd" "$_0"; then + ((type=_ble_attr_CMD_JOBS)) + elif [[ $type == "$_ble_attr_KEYWORD" ]]; then + ble/syntax/highlight/cmdtype1 "${cmd_type[1]}" "$cmd" + fi +} +_ble_syntax_highlight_filetype_version=-1 +function ble/syntax/highlight/cmdtype { + local cmd=$1 _0=$2 + if ((_ble_syntax_highlight_filetype_version!=_ble_edit_LINENO)); then + ble/gdict#clear _ble_syntax_highlight_filetype + ((_ble_syntax_highlight_filetype_version=_ble_edit_LINENO)) + fi + if local ret; ble/gdict#get _ble_syntax_highlight_filetype "$_0"; then + type=$ret + return 0 + fi + ble/syntax/highlight/cmdtype/.impl "$cmd" "$_0" + ble/gdict#set _ble_syntax_highlight_filetype "$_0" "$type" +} +function ble/syntax/highlight/filetype { + type= + local file=$1 + if [[ ( $OSTYPE == cygwin || $OSTYPE == msys ) && $file == //* ]]; then + [[ $file == // ]] && ((type=_ble_attr_FILE_DIR)) + [[ $type ]]; return "$?" + fi + if [[ -h $file ]]; then + if [[ -e $file ]]; then + ((type=_ble_attr_FILE_LINK)) + else + ((type=_ble_attr_FILE_ORPHAN)) + fi + elif [[ -e $file ]]; then + if [[ -d $file ]]; then + if [[ -k $file ]]; then + ((type=_ble_attr_FILE_STICKY)) + elif [[ -h ${file%/} ]]; then + ((type=_ble_attr_FILE_LINK)) + else + ((type=_ble_attr_FILE_DIR)) + fi + elif [[ -f $file ]]; then + if [[ -u $file ]]; then + ((type=_ble_attr_FILE_SETUID)) + elif [[ -g $file ]]; then + ((type=_ble_attr_FILE_SETGID)) + elif [[ -x $file ]]; then + ((type=_ble_attr_FILE_EXEC)) + else + ((type=_ble_attr_FILE_FILE)) + fi + elif [[ -c $file ]]; then + ((type=_ble_attr_FILE_CHR)) + elif [[ -p $file ]]; then + ((type=_ble_attr_FILE_FIFO)) + elif [[ -S $file ]]; then + ((type=_ble_attr_FILE_SOCK)) + elif [[ -b $file ]]; then + ((type=_ble_attr_FILE_BLK)) + fi + elif local rex='^https?://[^ ^`"<>\{|}]+$'; [[ $file =~ $rex ]]; then + ((type=_ble_attr_FILE_URL)) + fi + [[ $type ]] +} +function ble/syntax/highlight/ls_colors/.clear { + _ble_syntax_highlight_lscolors=() + ble/gdict#clear _ble_syntax_highlight_lscolors_ext +} +function ble/syntax/highlight/ls_colors/.register-extension { + local key=$1 value=$2 + ble/gdict#set _ble_syntax_highlight_lscolors_ext "$key" "$value" +} +function ble/syntax/highlight/ls_colors/.read-extension { + ble/gdict#get _ble_syntax_highlight_lscolors_ext "$1" +} +function ble/syntax/highlight/ls_colors/.parse { + ble/syntax/highlight/ls_colors/.clear + local fields field + ble/string#split fields : "$1" + for field in "${fields[@]}"; do + [[ $field == *=* ]] || continue + local lhs=${field%%=*} + local ret; ble/color/sgrspec2g "${field#*=}"; local rhs=$ret + case $lhs in + ('di') _ble_syntax_highlight_lscolors[_ble_attr_FILE_DIR]=$rhs ;; + ('st') _ble_syntax_highlight_lscolors[_ble_attr_FILE_STICKY]=$rhs ;; + ('ln') _ble_syntax_highlight_lscolors[_ble_attr_FILE_LINK]=$rhs ;; + ('or') _ble_syntax_highlight_lscolors[_ble_attr_FILE_ORPHAN]=$rhs ;; + ('fi') _ble_syntax_highlight_lscolors[_ble_attr_FILE_FILE]=$rhs ;; + ('su') _ble_syntax_highlight_lscolors[_ble_attr_FILE_SETUID]=$rhs ;; + ('sg') _ble_syntax_highlight_lscolors[_ble_attr_FILE_SETGID]=$rhs ;; + ('ex') _ble_syntax_highlight_lscolors[_ble_attr_FILE_EXEC]=$rhs ;; + ('cd') _ble_syntax_highlight_lscolors[_ble_attr_FILE_CHR]=$rhs ;; + ('pi') _ble_syntax_highlight_lscolors[_ble_attr_FILE_FIFO]=$rhs ;; + ('so') _ble_syntax_highlight_lscolors[_ble_attr_FILE_SOCK]=$rhs ;; + ('bd') _ble_syntax_highlight_lscolors[_ble_attr_FILE_BLK]=$rhs ;; + (\*.*) + ble/syntax/highlight/ls_colors/.register-extension "${lhs:2}" "$rhs" ;; + esac + done +} +function ble/syntax/highlight/ls_colors { + local file=$1 + if ((type==_ble_attr_FILE_FILE)); then + local ext=${file##*/} ret= + while [[ $ext == *.* ]]; do + ext=${ext#*.} + [[ $ext ]] || break + if ble/syntax/highlight/ls_colors/.read-extension "$ext"; then + type=g:$ret + return 0 + fi + done + fi + local g=${_ble_syntax_highlight_lscolors[type]} + if [[ $g ]]; then + type=g:$g + return 0 + fi + return 1 +} +function ble/syntax/highlight/getg-from-filename { + local filename=$1 type= + ble/syntax/highlight/filetype "$filename" + if [[ $bleopt_filename_ls_colors ]]; then + if ble/syntax/highlight/ls_colors "$filename" && [[ $type == g:* ]]; then + local ret; ble/color/face2g filename_ls_colors; g=$ret + ((g|=${type:2})) + return 0 + fi + fi + if [[ $type ]]; then + ble/syntax/attr2g "$type" + else + g= + fi +} +function bleopt/check:filename_ls_colors { + ble/syntax/highlight/ls_colors/.parse "$value" +} +bleopt -I filename_ls_colors +_ble_syntax_progcolor_vars=( + node TE_i TE_nofs wtype wlen wbeg wend wattr) +_ble_syntax_progcolor_wattr_vars=( + wattr_buff wattr_pos wattr_g) +function ble/progcolor/load-word-data { + TE_i=${1%%:*} TE_nofs=${1#*:} + [[ $1 != *:* ]] && TE_nofs=0 + ble/string#split-words node "${_ble_syntax_tree[TE_i-1]}" + wtype=${node[TE_nofs]} + wlen=${node[TE_nofs+1]} + wattr=${node[TE_nofs+4]} + wbeg=$((TE_i-wlen)) + wend=$TE_i +} +function ble/progcolor/set-wattr { + ble/syntax/urange#update color_ "$wbeg" "$wend" + ble/syntax/wrange#update _ble_syntax_word_ "$TE_i" + node[TE_nofs+4]=$1 + local IFS=$_ble_term_IFS + _ble_syntax_tree[TE_i-1]="${node[*]}" +} +function ble/progcolor/eval-word { + local iword=${1:-progcolor_iword} opts=$2 + if [[ ${progcolor_stats[iword]+set} ]]; then + ret=${progcolor_wvals[iword]} + return "${progcolor_stats[iword]}" + fi + local wtxt=${comp_words[iword]} + local simple_flags simple_ibrace + if ! ble/syntax:bash/simple-word/reconstruct-incomplete-word "$wtxt"; then + ret= + progcolor_stats[iword]=2 + progcolor_wvals[iword]= + return 2 + fi + ble/syntax:bash/simple-word/eval "$ret" "$opts"; local ext=$? + ((ext==148)) && return 148 + if ((ext!=0)); then + ret= + progcolor_stats[iword]=1 + progcolor_wvals[iword]= + return 1 + fi + progcolor_stats[iword]=0 + progcolor_wvals[iword]=$ret + return 0 +} +function ble/progcolor/load-cmdspec-opts { + if [[ $progcolor_cmdspec_opts ]]; then + cmdspec_opts=$progcolor_cmdspec_opts + else + ble/cmdspec/opts#load "${comp_words[0]}" + progcolor_cmdspec_opts=${cmdspec_opts:-:} + fi +} +function ble/progcolor/stop-option#init { + rexrej='^--$' rexreq= stopat= + local cmdspec_opts=$1 + if [[ $cmdspec_opts ]]; then + if [[ :$cmdspec_opts: == *:no-options:* ]]; then + stopat=0 + return 1 + elif ble/opts#extract-first-optarg "$cmdspec_opts" stop-options-at && [[ $ret ]]; then + ((stopat=ret)) + return 1 + fi + local ret + if ble/opts#extract-first-optarg "$cmdspec_opts" stop-options-on && [[ $ret ]]; then + rexrej=$ret + elif [[ :$cmdspec_opts: == *:disable-double-hyphen:* ]]; then + rexrej= + fi + if ble/opts#extract-first-optarg "$cmdspec_opts" stop-options-unless && [[ $ret ]]; then + rexreq=$ret + elif [[ :$cmdspec_opts: == *:stop-options-postarg:* ]]; then + rexreq='^-.+' + ble/opts#has "$cmdspec_opts" plus-options && rexreq='^[-+].+' + fi + fi +} +function ble/progcolor/stop-option#test { + [[ $rexrej && $1 =~ $rexrej || $rexreq && ! ( $1 =~ $rexreq ) ]] +} +function ble/progcolor/is-option-context { + if [[ ${progcolor_optctx[1]} ]]; then + ((progcolor_optctx[1]<0?1:(progcolor_iword<=progcolor_optctx[1]))) + return $? + fi + local rexrej rexreq stopat + if [[ ! ${progcolor_optctx[0]} ]]; then + progcolor_optctx[0]=1 + local cmdspec_opts + ble/progcolor/load-cmdspec-opts + ble/progcolor/stop-option#init "$cmdspec_opts" + if [[ ! $rexrej$rexreq ]]; then + progcolor_optctx[1]=${stopat:--1} + ((progcolor_optctx[1]<0?1:(progcolor_iword<=progcolor_optctx[1]))) + return $? + fi + progcolor_optctx[2]=$rexrej + progcolor_optctx[3]=$rexreq + progcolor_optctx[4]=$stopat + else + rexrej=${progcolor_optctx[2]} + rexreq=${progcolor_optctx[3]} + stopat=${progcolor_optctx[4]} + fi + [[ $stopat ]] && ((progcolor_iword>stopat)) && return 1 + local iword + for ((iword=progcolor_optctx[0];iword<progcolor_iword;iword++)); do + ble/progcolor/eval-word "$iword" "$highlight_eval_opts" + if ble/progcolor/stop-option#test "$ret"; then + progcolor_optctx[1]=$iword + return 1 + fi + done + progcolor_optctx[0]=$iword + return 0 +} +function ble/progcolor/wattr#initialize { + wattr_buff=() + wattr_pos=$wbeg + wattr_g=d +} +function ble/progcolor/wattr#setg { + local pos=$1 g=$2 + local len=$((pos-wattr_pos)) + ((len>0)) && ble/array#push wattr_buff "$len:$wattr_g" + wattr_pos=$pos + wattr_g=$g +} +function ble/progcolor/wattr#setattr { + local pos=$1 attr=$2 g + ble/syntax/attr2g "$attr" + ble/progcolor/wattr#setg "$pos" "$g" +} +function ble/progcolor/wattr#finalize { + local wattr + if ((${#wattr_buff[@]})); then + local len=$((wend-wattr_pos)) + ((len>0)) && ble/array#push wattr_buff \$:"$wattr_g" + wattr_pos=$wend + wattr_g=d + IFS=, builtin eval 'wattr="m${wattr_buff[*]}"' + else + wattr=$wattr_g + fi + ble/progcolor/set-wattr "$wattr" +} +function ble/progcolor/highlight-filename/.detect-separated-path { + local word=$1 + ((wtype==_ble_ctx_ARGI||wtype==_ble_ctx_ARGEI||wtype==_ble_ctx_VALI||wtype==_ble_attr_VAR||wtype==_ble_ctx_RDRS)) || return 1 + local detect_opts=url:$highlight_eval_opts + ((wtype==_ble_ctx_RDRS)) && detect_opts=$detect_opts:noglob + [[ $word == '~'* ]] && ((_ble_syntax_attr[p0]!=_ble_attr_TILDE)) && detect_opts=$detect_opts:notilde + ble/syntax:bash/simple-word/detect-separated-path "$word" :, "$detect_opts" +} +function ble/progcolor/highlight-filename/.pathspec.wattr { + local p=$p0 opts=$2 + if [[ :$opts: != *:no-path-color:* ]]; then + local ipath npath=${#path[@]} + for ((ipath=0;ipath<npath-1;ipath++)); do + local epath=${path[ipath]} espec=${spec[ipath]} + local g=d + if ble/syntax/util/is-directory "$epath"; then + local type + ble/syntax/highlight/filetype "$epath" && + ble/syntax/attr2g "$type" + elif ((wtype==_ble_ctx_CMDI)); then + ble/syntax/attr2g "$_ble_attr_ERR" + fi + ((wtype==_ble_ctx_CMDI&&(g&=~_ble_color_gflags_Underline))) + ble/progcolor/wattr#setg "$p" "$g" + ((p=p0+${#espec})) + done + fi + ble/progcolor/wattr#setg "$p" "$1" + [[ $1 != d ]] && + ble/progcolor/wattr#setg "$p1" d + return 0 +} +function ble/progcolor/highlight-filename/.pathspec-with-attr.wattr { + local g; ble/syntax/attr2g "$1" + ble/progcolor/highlight-filename/.pathspec.wattr "$g" + return 0 +} +function ble/progcolor/highlight-filename/.pathspec-by-name.wattr { + local value=$1 + local highlight_opts= + local type=; ble/syntax/highlight/filetype "$value" + ((type==_ble_attr_FILE_URL)) && highlight_opts=no-path-color + if ((wtype==_ble_ctx_RDRF||wtype==_ble_ctx_RDRD2)); then + if ((type==_ble_attr_FILE_DIR)); then + type=$_ble_attr_ERR + elif ((_ble_syntax_TREE_WIDTH<=TE_nofs)); then + local redirect_ntype=${node[TE_nofs-_ble_syntax_TREE_WIDTH]:1} + if [[ ( $redirect_ntype == *'>' || $redirect_ntype == '>'[\|\&] ) ]]; then + if [[ -e $value || -h $value ]]; then + if [[ -d $value || ! -w $value ]]; then + type=$_ble_attr_ERR + elif [[ ( $redirect_ntype == [\<\&]'>' || $redirect_ntype == '>' || $redirect_ntype == '>&' ) && -f $value ]]; then + if [[ -o noclobber ]]; then + type=$_ble_attr_ERR + else + type=$_ble_attr_FILE_WARN + fi + fi + elif [[ $value == */* && ! -w ${value%/*}/ || $value != */* && ! -w ./ ]]; then + type=$_ble_attr_ERR + fi + elif [[ $redirect_ntype == '<' && ! -r $value ]]; then + type=$_ble_attr_ERR + fi + fi + fi + local g= + if [[ $bleopt_filename_ls_colors ]]; then + if ble/syntax/highlight/ls_colors "$value" && [[ $type == g:* ]]; then + local ret; ble/color/face2g filename_ls_colors; g=$ret + type=g:$((${type:2}|g)) + fi + fi + [[ $type && ! $g ]] && ble/syntax/attr2g "$type" + ble/progcolor/highlight-filename/.pathspec.wattr "${g:-d}" "$highlight_opts" + return 0 +} +function ble/progcolor/highlight-filename/.single.wattr { + local p0=${1%%:*} p1=${1#*:} + local wtxt=${text:p0:p1-p0} + if ((wtype==_ble_ctx_CMDI)) && ble/alias#active "$wtxt"; then + ble/progcolor/wattr#setattr "$p0" "$_ble_attr_CMD_ALIAS" + return 0 + fi + local path_opts=after-sep:$highlight_eval_opts + [[ $wtxt == '~'* ]] && ((_ble_syntax_attr[p0]!=_ble_attr_TILDE)) && path_opts=$path_opts:notilde + ((wtype==_ble_ctx_RDRS||wtype==_ble_attr_VAR||wtype==_ble_ctx_VALI&&wbeg<p0)) && path_opts=$path_opts:noglob + local ret path spec ext value count + ble/syntax:bash/simple-word/evaluate-path-spec "$wtxt" / "count:$path_opts"; ext=$? value=("${ret[@]}") + ((ext==148)) && return 148 + if ((ext==142)); then + if [[ $ble_textarea_render_defer_running ]]; then + ble/progcolor/wattr#setg "$p0" d + else + return 148 + fi + elif ((ext&&(wtype==_ble_ctx_CMDI||wtype==_ble_ctx_ARGI||wtype==_ble_ctx_ARGEI||wtype==_ble_ctx_RDRF||wtype==_ble_ctx_RDRS||wtype==_ble_ctx_RDRD||wtype==_ble_ctx_RDRD2||wtype==_ble_ctx_VALI))); then + ble/progcolor/highlight-filename/.pathspec-with-attr.wattr "$_ble_attr_ERR" + elif (((wtype==_ble_ctx_RDRF||wtype==_ble_ctx_RDRD||wtype==_ble_ctx_RDRD2)&&count>=2)); then + ble/progcolor/wattr#setattr "$p0" "$_ble_attr_ERR" + elif ((wtype==_ble_ctx_CMDI)); then + local attr=${_ble_syntax_attr[wbeg]} + if ((attr!=_ble_attr_KEYWORD&&attr!=_ble_attr_KEYWORD_BEGIN&&attr!=_ble_attr_KEYWORD_END&&attr!=_ble_attr_KEYWORD_MID&&attr!=_ble_attr_DEL)); then + local type=; ble/syntax/highlight/cmdtype "$value" "$wtxt" + if ((type==_ble_attr_CMD_FILE||type==_ble_attr_CMD_FILE||type==_ble_attr_ERR)); then + ble/progcolor/highlight-filename/.pathspec-with-attr.wattr "$type" + elif [[ $type ]]; then + ble/progcolor/wattr#setattr "$p0" "$type" + fi + fi + elif ((wtype==_ble_ctx_RDRD||wtype==_ble_ctx_RDRD2)); then + if local rex='^[0-9]+-?$|^-$'; [[ $value =~ $rex ]]; then + ble/progcolor/wattr#setattr "$p0" "$_ble_attr_DEL" + elif ((wtype==_ble_ctx_RDRD2)); then + ble/progcolor/highlight-filename/.pathspec-by-name.wattr "$value" + else + ble/progcolor/wattr#setattr "$p0" "$_ble_attr_ERR" + fi + elif ((wtype==_ble_ctx_ARGI||wtype==_ble_ctx_ARGEI||wtype==_ble_ctx_VALI||wtype==_ble_attr_VAR||wtype==_ble_ctx_RDRS||wtype==_ble_ctx_RDRF)); then + ble/progcolor/highlight-filename/.pathspec-by-name.wattr "$value" + fi +} +function ble/progcolor/highlight-filename.wattr { + local p0=$1 p1=$2 + if ((p0<p1)) && [[ $bleopt_highlight_filename ]]; then + local wtxt=${text:p0:p1-p0} + local ret; ble/progcolor/highlight-filename/.detect-separated-path "$wtxt"; local ext=$? + ((ext==148)) && return 148 + if ((ext==0)); then + local sep=$ret ranges i + ble/syntax:bash/simple-word/locate-filename "$wtxt" "$sep" "url:$highlight_eval_opts" + (($?==148)) && return 148; ranges=("${ret[@]}") + for ((i=0;i<${#ranges[@]};i+=2)); do + ble/progcolor/highlight-filename/.single.wattr $((p0+ranges[i])):$((p0+ranges[i+1])) + (($?==148)) && return 148 + done + elif ble/syntax:bash/simple-word/is-simple "$wtxt"; then + ble/progcolor/highlight-filename/.single.wattr "$p0":"$p1" + (($?==148)) && return 148 + fi + fi +} +function ble/progcolor/@wattr { + [[ $wtype =~ ^[0-9]+$ ]] || return 1 + [[ $wattr == - ]] || return 1 + local "${_ble_syntax_progcolor_wattr_vars[@]/%/=}" # WA #D1570 checked + ble/progcolor/wattr#initialize + "$@"; local ext=$? + if ((ext==148)); then + _ble_textarea_render_defer=1 + ble/syntax/wrange#update _ble_syntax_word_defer_ "$wend" + else + ble/progcolor/wattr#finalize + fi + return "$ext" +} +function ble/progcolor/word:default/.is-option { + ((wtype==_ble_ctx_ARGI||wtype==_ble_ctx_ARGEI||wtype==_ble_ctx_ARGVI)) && + ble/string#match "$1" '^(-[-_a-zA-Z0-9]*)=?' && # 高速な判定を先に済ませる + ble/progcolor/is-option-context && + ble/string#match "$1" '^(-[-_a-zA-Z0-9]*)=?' # 再実行 for BASH_REMATCH +} +function ble/progcolor/word:default/impl.wattr { + if ((wtype==_ble_ctx_RDRH||wtype==_ble_ctx_RDRI||wtype==_ble_attr_FUNCDEF||wtype==_ble_attr_ERR)); then + ble/progcolor/wattr#setattr "$wbeg" "$wtype" + else + local p0=$wbeg p1=$wend wtxt=${text:wbeg:wlen} + if ((wtype==_ble_attr_VAR||wtype==_ble_ctx_VALI)); then + local ret + ble/syntax:bash/find-rhs "$wtype" "$wbeg" "$wlen" element-assignment && p0=$ret + elif ((wtype==_ble_ctx_ARGI||wtype==_ble_ctx_ARGEI||wtype==_ble_ctx_VALI)) && { local rex='^[_a-zA-Z][_a-zA-Z0-9]*='; [[ $wtxt =~ $rex ]]; }; then + ((p0+=${#BASH_REMATCH})) + elif ble/progcolor/word:default/.is-option "$wtxt"; then + local rematch=$BASH_REMATCH rematch1=${BASH_REMATCH[1]} + local ret; ble/color/face2g argument_option + ble/progcolor/wattr#setg "$p0" "$ret" + ble/progcolor/wattr#setg $((p0+${#rematch1})) d + ((p0+=${#rematch})) + fi + ble/progcolor/highlight-filename.wattr "$p0" "$p1" + (($?==148)) && return 148 + fi + return 0 +} +function ble/progcolor/word:default { + ble/progcolor/@wattr ble/progcolor/word:default/impl.wattr +} +function ble/progcolor/default { + local i "${_ble_syntax_progcolor_vars[@]/%/=}" # WA #D1570 checked + for ((i=1;i<${#comp_words[@]};i++)); do + local ref=${tree_words[i]} + [[ $ref ]] || continue + local progcolor_iword=$i + ble/progcolor/load-word-data "$ref" + ble/progcolor/word:default + done +} +function ble/progcolor/.compline-rewrite-command { + local ocmd=${comp_words[0]} + [[ $1 != "$ocmd" ]] || (($#>=2)) || return 1 + local IFS=$_ble_term_IFS + local ins="$*" + comp_line=$ins${comp_line:${#ocmd}} + ((comp_point-=${#ocmd},comp_point<0&&(comp_point=0),comp_point+=${#ins})) + comp_words=("$@" "${comp_words[@]:1}") + ((comp_cword&&(comp_cword+=$#-1))) + ble/array#reserve-prototype $# + tree_words=("${tree_words[0]}" "${_ble_array_prototype[@]::$#-1}" "${tree_words[@]:1}") +} +function ble/progcolor { + local cmd=$1 opts=$2 + local -a progcolor_stats=() + local -a progcolor_wvals=() + local progcolor_cmdspec_opts= + local -a progcolor_optctx=() + local -a alias_args=() + local checked=" " processed= + while :; do + if ble/is-function ble/cmdinfo/cmd:"$cmd"/chroma; then + ble/progcolor/.compline-rewrite-command "$cmd" "${alias_args[@]}" + ble/cmdinfo/cmd:"$cmd"/chroma "$opts" + processed=1 + break + elif [[ $cmd == */?* ]] && ble/is-function ble/cmdinfo/cmd:"${cmd##*/}"/chroma; then + ble/progcolor/.compline-rewrite-command "${cmd##*/}" "${alias_args[@]}" + ble/cmdinfo/cmd:"${cmd##*/}"/chroma "$opts" + processed=1 + break + fi + checked="$checked$cmd " + local ret + ble/alias#expand "$cmd" + ble/string#split-words ret "$ret" + [[ $checked == *" $ret "* ]] && break + cmd=$ret + ((${#ret[@]}>=2)) && + alias_args=("${ret[@]:1}" "${alias_args[@]}") + done + [[ $processed ]] || + ble/progcolor/default + if [[ ${tree_words[0]} ]]; then + local "${_ble_syntax_progcolor_vars[@]/%/=}" # WA #D1570 checked + ble/progcolor/load-word-data "${tree_words[0]}" + [[ $wattr == - ]] && ble/progcolor/word:default + fi +} +function ble/highlight/layer:syntax/touch-range { + ble/syntax/urange#update '' "$@" +} +function ble/highlight/layer:syntax/fill { + local _i _arr=$1 _i1=$2 _i2=$3 _v=$4 + for ((_i=_i1;_i<_i2;_i++)); do + builtin eval "$_arr[_i]=\"\$_v\"" + done +} +_ble_highlight_layer_syntax_VARNAMES=( + _ble_highlight_layer_syntax_buff + _ble_highlight_layer_syntax_active + _ble_highlight_layer_syntax1_table + _ble_highlight_layer_syntax2_table + _ble_highlight_layer_syntax3_list + _ble_highlight_layer_syntax3_table) +function ble/highlight/layer:syntax/initialize-vars { + _ble_highlight_layer_syntax_buff=() + _ble_highlight_layer_syntax1_table=() + _ble_highlight_layer_syntax2_table=() + _ble_highlight_layer_syntax3_list=() + _ble_highlight_layer_syntax3_table=() # errors +} +ble/highlight/layer:syntax/initialize-vars +function ble/highlight/layer:syntax/update-attribute-table { + ble/highlight/layer/update/shift _ble_highlight_layer_syntax1_table + if ((_ble_syntax_attr_umin>=0)); then + ble/highlight/layer:syntax/touch-range _ble_syntax_attr_umin _ble_syntax_attr_umax + local i g=0 + ((_ble_syntax_attr_umin>0)) && + ((g=_ble_highlight_layer_syntax1_table[_ble_syntax_attr_umin-1])) + for ((i=_ble_syntax_attr_umin;i<_ble_syntax_attr_umax;i++)); do + if ((${_ble_syntax_attr[i]})); then + ble/syntax/attr2g "${_ble_syntax_attr[i]}" + fi + _ble_highlight_layer_syntax1_table[i]=$g + done + _ble_syntax_attr_umin=-1 _ble_syntax_attr_umax=-1 + fi +} +function ble/highlight/layer:syntax/word/.update-attributes/.proc { + [[ $wtype =~ ^[0-9]+$ ]] || return 1 + [[ ${node[TE_nofs+4]} == - ]] || return 1 + if ((wtype==_ble_ctx_CMDI||wtype==_ble_ctx_ARGI||wtype==_ble_ctx_ARGVI||wtype==_ble_ctx_ARGEI)); then + local comp_line comp_point comp_words comp_cword tree_words + if ble/syntax:bash/extract-command-by-noderef "$TE_i:$TE_nofs" treeinfo; then + local cmd=${comp_words[0]} + ble/progcolor "$cmd" + return 0 + fi + fi + ble/progcolor/word:default +} +function ble/highlight/layer:syntax/word/.update-attributes { + ((_ble_syntax_word_umin>=0)) || return 1 + if [[ ! $ble_textarea_render_defer_running ]]; then + local _ble_syntax_bash_simple_eval_timeout=$bleopt_highlight_timeout_sync + local _ble_syntax_bash_simple_eval_timeout_carry= + local highlight_eval_opts=cached:single:stopcheck:timeout-carry + else + local _ble_syntax_bash_simple_eval_timeout=$bleopt_highlight_timeout_async + local highlight_eval_opts=cached:single:stopcheck + fi + ble/syntax/tree-enumerate-in-range "$_ble_syntax_word_umin" "$_ble_syntax_word_umax" \ + ble/highlight/layer:syntax/word/.update-attributes/.proc +} +function ble/highlight/layer:syntax/word/.apply-attribute { + local wbeg=$1 wend=$2 wattr=$3 + ((wbeg<color_umin&&(wbeg=color_umin), + wend>color_umax&&(wend=color_umax), + wbeg<wend)) || return 1 + if [[ $wattr =~ ^[0-9]+$ ]]; then + ble/array#fill-range _ble_highlight_layer_syntax2_table "$wbeg" "$wend" "$wattr" + elif [[ $wattr == m* ]]; then + local ranges; ble/string#split ranges , "${wattr:1}" + local i=$wbeg j range + for range in "${ranges[@]}"; do + local len=${range%%:*} sub_wattr=${range#*:} + if [[ $len == '$' ]]; then + j=$wend + else + ((j=i+len,j>wend&&(j=wend))) + fi + ble/highlight/layer:syntax/word/.apply-attribute "$i" "$j" "$sub_wattr" + (((i=j)<wend)) || break + done + elif [[ $wattr == d ]]; then + ble/array#fill-range _ble_highlight_layer_syntax2_table "$wbeg" "$wend" '' + fi +} +function ble/highlight/layer:syntax/word/.proc-childnode { + if [[ $wtype =~ ^[0-9]+$ ]]; then + local wbeg=$wbegin wend=$TE_i + ble/highlight/layer:syntax/word/.apply-attribute "$wbeg" "$wend" "$attr" + fi + ((tchild>=0)) && ble/syntax/tree-enumerate-children "$proc_children" +} +function ble/highlight/layer:syntax/update-word-table { + local color_umin=-1 color_umax=-1 iN=${#_ble_syntax_text} + ble/highlight/layer:syntax/word/.update-attributes + ble/highlight/layer/update/shift _ble_highlight_layer_syntax2_table + ble/syntax/wrange#update _ble_syntax_word_ "$_ble_syntax_vanishing_word_umin" "$_ble_syntax_vanishing_word_umax" + ble/syntax/wrange#update color_ "$_ble_syntax_vanishing_word_umin" "$_ble_syntax_vanishing_word_umax" + _ble_syntax_vanishing_word_umin=-1 _ble_syntax_vanishing_word_umax=-1 + ble/highlight/layer:syntax/word/.apply-attribute 0 "$iN" d # clear word color + local TE_i + for ((TE_i=_ble_syntax_word_umax;TE_i>=_ble_syntax_word_umin;)); do + if ((TE_i>0)) && [[ ${_ble_syntax_tree[TE_i-1]} ]]; then + local -a node + ble/string#split-words node "${_ble_syntax_tree[TE_i-1]}" + local wlen=${node[1]} + local wbeg=$((TE_i-wlen)) wend=$TE_i + if [[ ${node[0]} =~ ^[0-9]+$ ]]; then + local attr=${node[4]} + ble/highlight/layer:syntax/word/.apply-attribute "$wbeg" "$wend" "$attr" + fi + local tclen=${node[2]} + if ((tclen>=0)); then + local tchild=$((TE_i-tclen)) + local tree= TE_nofs=0 proc_children=ble/highlight/layer:syntax/word/.proc-childnode + ble/syntax/tree-enumerate-children "$proc_children" + fi + ((TE_i=wbeg)) + else + ((TE_i--)) + fi + done + ((color_umin>=0)) && ble/highlight/layer:syntax/touch-range "$color_umin" "$color_umax" + _ble_syntax_word_umin=-1 _ble_syntax_word_umax=-1 +} +function ble/highlight/layer:syntax/update-error-table/set { + local i1=$1 i2=$2 g=$3 + if ((i1<i2)); then + ble/highlight/layer:syntax/touch-range "$i1" "$i2" + ble/highlight/layer:syntax/fill _ble_highlight_layer_syntax3_table "$i1" "$i2" "$g" + _ble_highlight_layer_syntax3_list[${#_ble_highlight_layer_syntax3_list[@]}]="$i1 $i2" + fi +} +function ble/highlight/layer:syntax/update-error-table { + ble/highlight/layer/update/shift _ble_highlight_layer_syntax3_table + local j=0 jN=${#_ble_highlight_layer_syntax3_list[*]} + if ((jN)); then + for ((j=0;j<jN;j++)); do + local -a range + ble/string#split-words range "${_ble_highlight_layer_syntax3_list[j]}" + local a=${range[0]} b=${range[1]} + ((a>=DMAX0?(a+=DMAX-DMAX0):(a>=DMIN&&(a=DMIN)), + b>=DMAX0?(b+=DMAX-DMAX0):(b>=DMIN&&(b=DMIN)))) + if ((a<b)); then + ble/highlight/layer:syntax/fill _ble_highlight_layer_syntax3_table "$a" "$b" '' + ble/highlight/layer:syntax/touch-range "$a" "$b" + fi + done + _ble_highlight_layer_syntax3_list=() + fi + if ((iN>0)) && [[ ${_ble_syntax_stat[iN]} ]]; then + local ret; ble/color/face2g syntax_error; local g=$ret + local -a stat + ble/string#split-words stat "${_ble_syntax_stat[iN]}" + local ctx=${stat[0]} nlen=${stat[3]} nparam=${stat[6]} + [[ $nparam == none ]] && nparam= + local i inest + if ((nlen>0)) || [[ $nparam ]]; then + ble/highlight/layer:syntax/update-error-table/set $((iN-1)) "$iN" "$g" + if ((nlen>0)); then + ((inest=iN-nlen)) + while ((inest>=0)); do + local inest2 + for((inest2=inest+1;inest2<iN;inest2++)); do + [[ ${_ble_syntax_attr[inest2]} ]] && break + done + ble/highlight/layer:syntax/update-error-table/set "$inest" "$inest2" "$g" + ((i=inest)) + local wtype wbegin tchild tprev + ble/syntax/parse/nest-pop + ((inest>=i&&(inest=i-1))) + done + fi + fi + if ((ctx==_ble_ctx_CMDX1||ctx==_ble_ctx_CMDXC||ctx==_ble_ctx_FARGX1||ctx==_ble_ctx_SARGX1||ctx==_ble_ctx_FARGX2||ctx==_ble_ctx_CARGX1||ctx==_ble_ctx_CARGX2||ctx==_ble_ctx_COARGX)); then + ble/highlight/layer:syntax/update-error-table/set $((iN-1)) "$iN" "$g" + fi + fi +} +function ble/highlight/layer:syntax/update { + local text=$1 player=$2 + local i iN=${#text} + local umin=-1 umax=-1 + ((DMIN>=0)) && umin=$DMIN umax=$DMAX + if [[ ! $bleopt_highlight_syntax ]]; then + if [[ $_ble_highlight_layer_syntax_active ]]; then + _ble_highlight_layer_syntax_active= + PREV_UMIN=0 PREV_UMAX=${#1} + fi + return + fi + if [[ ! $_ble_highlight_layer_syntax_active ]]; then + _ble_highlight_layer_syntax_active=1 + umin=0 umax=${#text} + fi + if [[ $bleopt_syntax_debug ]]; then + local debug_attr_umin=$_ble_syntax_attr_umin + local debug_attr_uend=$_ble_syntax_attr_umax + fi + ble/cmdspec/initialize # load chroma + ble/highlight/layer:syntax/update-attribute-table + ble/highlight/layer:syntax/update-word-table + ble/highlight/layer:syntax/update-error-table + if ((DMIN>=0)); then + ble/highlight/layer/update/shift _ble_highlight_layer_syntax_buff + if ((DMAX>0)); then + local g sgr ch ret + ble/highlight/layer:syntax/getg "$DMAX" + ble/color/g2sgr "$g"; sgr=$ret + ch=${_ble_highlight_layer_plain_buff[DMAX]} + _ble_highlight_layer_syntax_buff[DMAX]=$sgr$ch + fi + fi + local i j g gprev=0 + if ((umin>0)); then + ble/highlight/layer:syntax/getg $((umin-1)) + gprev=$g + fi + if ((umin>=0)); then + local ret + for ((i=umin;i<=umax;i++)); do + local ch=${_ble_highlight_layer_plain_buff[i]} + ble/highlight/layer:syntax/getg "$i" + [[ $g ]] || ble/highlight/layer/update/getg "$i" + if ((gprev!=g)); then + ble/color/g2sgr "$g" + ch=$ret$ch + ((gprev=g)) + fi + _ble_highlight_layer_syntax_buff[i]=$ch + done + fi + PREV_UMIN=$umin PREV_UMAX=$umax + PREV_BUFF=_ble_highlight_layer_syntax_buff + if [[ $bleopt_syntax_debug ]]; then + local status buff= nl=$'\n' + _ble_syntax_attr_umin=$debug_attr_umin _ble_syntax_attr_umax=$debug_attr_uend ble/syntax/print-status -v status + local -a DRAW_BUFF=() + ble/syntax/print-layer-buffer.draw plain + ble/syntax/print-layer-buffer.draw syntax + ble/syntax/print-layer-buffer.draw disabled + ble/syntax/print-layer-buffer.draw region + ble/syntax/print-layer-buffer.draw overwrite + local ret; ble/canvas/sflush.draw + status=$status$ret + ble/edit/info/show ansi "$status" + fi +} +function ble/highlight/layer:syntax/getg { + [[ ! $bleopt_highlight_syntax ]] && return + local i=$1 + if [[ ${_ble_highlight_layer_syntax3_table[i]} ]]; then + g=${_ble_highlight_layer_syntax3_table[i]} + elif [[ ${_ble_highlight_layer_syntax2_table[i]} ]]; then + g=${_ble_highlight_layer_syntax2_table[i]} + elif [[ ${_ble_highlight_layer_syntax1_table[i]} ]]; then + g=${_ble_highlight_layer_syntax1_table[i]} + fi +} +function ble/highlight/layer:syntax/textarea_render_defer.hook { + ble/syntax/wrange#update _ble_syntax_word_ "$_ble_syntax_word_defer_umin" "$_ble_syntax_word_defer_umax" + _ble_syntax_word_defer_umin=-1 + _ble_syntax_word_defer_umax=-1 +} +blehook textarea_render_defer+=ble/highlight/layer:syntax/textarea_render_defer.hook +function ble/syntax/import { :; } +blehook/invoke syntax_load +ble/function#try ble/textarea#invalidate str +return 0 diff --git a/.local/src/blesh/lib/core-test.sh b/.local/src/blesh/lib/core-test.sh new file mode 100644 index 0000000..6adda33 --- /dev/null +++ b/.local/src/blesh/lib/core-test.sh @@ -0,0 +1,200 @@ +# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license +function ble/test/getdir { + dir=$_ble_base_run/$$.test + [[ -d $dir ]] || ble/bin/mkdir -p "$dir" +} +_ble_test_dir= +function ble/test/chdir { + local dir + ble/test/getdir + ble/util/getpid + _ble_test_dir=$dir/$BASHPID.d + [[ -d $_ble_test_dir ]] || + ble/bin/mkdir -p "$_ble_test_dir" + cd "$_ble_test_dir" +} +function ble/test/rmdir { + [[ -d $_ble_test_dir ]] && + ble/bin/rm -rf "$_ble_test_dir" + return 0 +} +_ble_test_logfile_fd= +function ble/test/log { + if [[ $_ble_test_logfile_fd ]]; then + ble/util/print "$1" >&$_ble_test_logfile_fd + fi + ble/util/print "$1" +} +function ble/test/log#open { + local file=$1 + if ble/fd#alloc _ble_test_logfile_fd '>>$file'; then + local h10=---------- + [[ -s $file ]] && + ble/util/print "$h10$h10$h10$h10$h10$h10$h10" >&$_ble_test_logfile_fd + ble/util/print "[$(date +'%F %T %Z')] test: start logging" >&$_ble_test_logfile_fd + fi +} +function ble/test/log#close { + if [[ $_ble_test_logfile_fd ]]; then + ble/util/print "[$(date +'%F %T %Z')] test: end logging" >&$_ble_test_logfile_fd + ble/fd#close _ble_test_logfile_fd + _ble_test_logfile_fd= + fi +} +if ble/bin/.freeze-utility-path colored; then + function ble/test/diff.impl { + ble/bin/colored diff -u "$@" + } +else + function ble/test/diff.impl { + diff -u "$@" + } +fi +function ble/test/diff { + local dir + ble/test/getdir + ble/util/getpid + local f1=$BASHPID.$1.expect + local f2=$BASHPID.$1.result + ( + cd "$dir" + ble/util/print "$2" >| "$f1" + ble/util/print "$3" >| "$f2" + ble/util/assign ret 'ble/test/diff.impl "$f1" "$f2"' + ble/test/log "$ret" + >| "$f1" >| "$f2" + ) +} +_ble_test_section_fd= +_ble_test_section_file= +_ble_test_section_title=section +_ble_test_section_count=0 +function ble/test/start-section { + [[ $_ble_test_section_fd ]] && ble/test/end-section + _ble_test_section_title=$1 + _ble_test_section_count=$2 + local dir + ble/test/getdir + ble/util/getpid + _ble_test_section_file=$dir/$BASHPID + ble/fd#alloc _ble_test_section_fd '> "$_ble_test_section_file"' +} +function ble/test/end-section { + [[ $_ble_test_section_fd ]] || return 1 + ble/fd#close _ble_test_section_fd + _ble_test_section_fd= + local ntest npass count=$_ble_test_section_count + local ntest nfail npass + builtin eval -- $( + ble/bin/awk ' + BEGIN{test=0;fail=0;pass=0;} + /^test /{test++} + /^fail /{fail++} + /^pass /{pass++} + END{print "ntest="test" nfail="fail" npass="pass;} + ' "$_ble_test_section_file") + local sgr=$'\e[32m' sgr0=$'\e[m' + ((npass==ntest)) || sgr=$'\e[31m' + local ncrash=$((ntest-nfail-npass)) + local nskip=$((count-ntest)) + if ((ntest)); then + local percentage=$((npass*1000/ntest)) # Note: 切り捨て + ble/util/sprintf percentage '%6s' "$((percentage/10)).$((percentage%10))%" # "XXX.X%" + else + local percentage=---.-% + fi + ble/test/log "$sgr$percentage$sgr0 [section] $_ble_test_section_title: $sgr$npass/$ntest$sgr0 ($nfail fail, $ncrash crash, $nskip skip)" + ((npass==ntest)) +} +function ble/test/section#incr { + local title=$1 + [[ $_ble_test_section_fd ]] || return 1 + ble/util/print "test $title" >&$_ble_test_section_fd +} +function ble/test/section#report { + local ext=$? title=$1 + [[ $_ble_test_section_fd ]] || return 1 + local code=fail; ((ext==0)) && code=pass + ble/util/print "$code $title" >&$_ble_test_section_fd +} +function ble/test/.read-arguments { + local _stdout _stderr _exit _ret + local qstdout qstderr qexit qret + local -a buff=() + while (($#)); do + local arg=$1; shift + case $arg in + ('#'*) + local ret; ble/string#trim "${arg#'#'}" + title=$ret ;; + (stdout[:=]*) + [[ $qstdout ]] && _stdout=$_stdout$'\n' + qstdout=1 + _stdout=$_stdout${arg#*[:=]} ;; + (stderr[:=]*) + [[ $qstderr ]] && _stderr=$_stderr$'\n' + qstderr=1 + _stderr=$_stderr${arg#*[:=]} ;; + (ret[:=]*) + qret=1 + _ret=${arg#*[:=]} ;; + (exit[:=]*) + qexit=1 + _exit=${arg#*[:=]} ;; + (code[:=]*) + ((${#buff[@]})) && ble/array#push buff $'\n' + ble/array#push buff "${arg#*[:=]}" ;; + (--depth=*) + caller_depth=${arg#*=} ;; + (--display-code=*) + display_code=${arg#*=} ;; + (*) + ((${#buff[@]})) && ble/array#push buff ' ' + ble/array#push buff "$arg" ;; + esac + done + [[ $qstdout ]] && item_expect[0]=$_stdout + [[ $qstderr ]] && item_expect[1]=$_stderr + [[ $qexit ]] && item_expect[2]=$_exit + [[ $qret ]] && item_expect[3]=$_ret + ((${#item_expect[@]})) || item_expect[2]=0 + IFS= builtin eval 'code="${buff[*]}"' +} +function ble/test { + local -a item_name=(stdout stderr exit ret) + local code title + local caller_depth=0 display_code= + local -a item_expect=() + ble/test/.read-arguments "$@" + local caller_lineno=${BASH_LINENO[caller_depth+0]} + local caller_source=${BASH_SOURCE[caller_depth+1]} + title="$caller_source:$caller_lineno${title+ ($title)}" + ble/test/section#incr "$title" + ble/util/assign stderr ' + ble/util/assign stdout "$code" 2>&1'; exit=$? + local -a item_result=() + item_result[0]=$stdout + item_result[1]=$stderr + item_result[2]=$exit + item_result[3]=$ret + local i flag_error= + for i in "${!item_expect[@]}"; do + [[ ${item_result[i]} == "${item_expect[i]}" ]] && continue + if [[ ! $flag_error ]]; then + flag_error=1 + ble/test/log $'\e[1m'"$title"$'\e[m: \e[91m'"${display_code:-$code}"$'\e[m' + fi + ble/test/diff "${item_name[i]}" "${item_expect[i]}" "${item_result[i]}" + done + if [[ $flag_error ]]; then + if [[ ! ${item_expect[1]+set} && $stderr ]]; then + ble/test/log "<STDERR>" + ble/test/log "$stderr" + ble/test/log "</STDERR>" + fi + ble/test/log + fi + [[ ! $flag_error ]] + ble/test/section#report "$title" + return 0 +} diff --git a/.local/src/blesh/lib/init-bind.sh b/.local/src/blesh/lib/init-bind.sh new file mode 100644 index 0000000..056654b --- /dev/null +++ b/.local/src/blesh/lib/init-bind.sh @@ -0,0 +1,92 @@ +# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license +function ble/init:bind/append { + local xarg="\"$1\":ble-decode/.hook $2; builtin eval -- \"\$_ble_decode_bind_hook\"" + local rarg=$1 condition=$3${3:+' && '} + ble/util/print "${condition}builtin bind -x '${xarg//$q/$Q}'" >> "$fbind1" + ble/util/print "${condition}builtin bind -r '${rarg//$q/$Q}'" >> "$fbind2" +} +function ble/init:bind/append-macro { + local kseq1=$1 kseq2=$2 condition=$3${3:+' && '} + local sarg="\"$kseq1\":\"$kseq2\"" rarg=$kseq1 + ble/util/print "${condition}builtin bind '${sarg//$q/$Q}'" >> "$fbind1" + ble/util/print "${condition}builtin bind -r '${rarg//$q/$Q}'" >> "$fbind2" +} +function ble/init:bind/generate-binder { + local fbind1=$_ble_base_cache/decode.bind.$_ble_bash.$bleopt_input_encoding.bind + local fbind2=$_ble_base_cache/decode.bind.$_ble_bash.$bleopt_input_encoding.unbind + ble/edit/info/show text "ble.sh: updating binders..." + : >| "$fbind1" + : >| "$fbind2" + local q=\' Q="'\\''" + local altdqs24='\xC0\x98' + local altdqs27='\xC0\x9B' + local esc00=$((40300<=_ble_bash&&_ble_bash<50000)) + local bind18XX=0 + if ((40400<=_ble_bash&&_ble_bash<50000)); then + ble/util/print "[[ -o emacs ]] && builtin bind 'set keyseq-timeout 1'" >> "$fbind1" + fbind2=$fbind1 ble/init:bind/append '\C-x\C-x' 24 '[[ -o emacs ]]' + elif ((_ble_bash<40300)); then + bind18XX=1 + fi + local esc1B=3 + local esc1B5B=1 bindAllSeq=0 + local esc1B1B=$((40100<=_ble_bash&&_ble_bash<40300)) + local i + for i in {128..255} {0..127}; do + local ret; ble/decode/c2dqs "$i" + if ((i==0)); then + if ((esc00)); then + ble/init:bind/append-macro '\C-@' '\xC0\x80' + else + ble/init:bind/append "$ret" "$i" + fi + elif ((i==24)); then + if ((bind18XX)); then + ble/init:bind/append "$ret" "$i" '[[ ! -o emacs ]]' + else + ble/init:bind/append "$ret" "$i" + fi + elif ((i==27)); then + if ((esc1B==0)); then + ble/init:bind/append "$ret" "$i" + elif ((esc1B==2)); then + ble/init:bind/append-macro '\e' "$altdqs27" + elif ((esc1B==3)); then + ble/init:bind/append-macro '\e' '\xDF\xBF' # C-[ + fi + else + ((i==28&&_ble_bash>=50000)) && ret='\x1C' + ble/init:bind/append "$ret" "$i" + fi + if ((bind18XX)); then + if ((i==24)); then + ble/init:bind/append-macro "\C-x$ret" "$altdqs24$altdqs24" '[[ -o emacs ]]' + else + ble/init:bind/append-macro "\C-x$ret" "$altdqs24$ret" '[[ -o emacs ]]' + fi + fi + if ((esc1B==3)); then + ble/init:bind/append-macro '\e'"$ret" "$altdqs27$ret" + else + if ((esc1B==1)); then + if ((i==91&&esc1B5B)); then + ble/init:bind/append-macro '\e[' "$altdqs27[" + else + ble/init:bind/append "\\e$ret" "27 $i" + fi + fi + if ((i==27&&esc1B1B)); then + ble/init:bind/append-macro '\e\e' '\e[^' + ble/util/print "ble-bind -k 'ESC [ ^' __esc__" >> "$fbind1" + ble/util/print "ble-bind -f __esc__ '.CHARS 27 27'" >> "$fbind1" + fi + fi + done + if ((bindAllSeq)); then + ble/util/print 'source "$_ble_decode_bind_fbinder.bind"' >> "$fbind1" + ble/util/print 'source "$_ble_decode_bind_fbinder.unbind"' >> "$fbind2" + fi + ble/function#try ble/encoding:"$bleopt_input_encoding"/generate-binder + ble/edit/info/immediate-show text "ble.sh: updating binders... done" +} +ble/init:bind/generate-binder diff --git a/.local/src/blesh/lib/init-cmap.sh b/.local/src/blesh/lib/init-cmap.sh new file mode 100644 index 0000000..1a2b4ef --- /dev/null +++ b/.local/src/blesh/lib/init-cmap.sh @@ -0,0 +1,186 @@ +# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license +function ble/init:cmap/bind-single-csi { + ble-bind -k "ESC [ $1" "$2" + ble-bind -k "CSI $1" "$2" +} +function ble/init:cmap/bind-single-ss3 { + ble-bind -k "ESC O $1" "$2" + ble-bind -k "SS3 $1" "$2" +} +function ble/init:cmap/bind-keypad-key { + local Ft=$1 name=$2 + (($3&4)) && ble-bind --csi "$Ft" "$name" + (($3&1)) && ble/init:cmap/bind-single-ss3 "$Ft" "$name" + (($3&2)) && ble-bind -k "ESC ? $Ft" "$name" +} +function ble/init:cmap/initialize { + ble/edit/info/immediate-show text "ble/lib/init-cmap.sh: updating key sequences..." + ble-decode-kbd/generate-keycode insert + ble-decode-kbd/generate-keycode home + ble-decode-kbd/generate-keycode prior + ble-decode-kbd/generate-keycode delete + ble-decode-kbd/generate-keycode end + ble-decode-kbd/generate-keycode next + ble-decode-kbd/generate-keycode find + ble-decode-kbd/generate-keycode select + local kend; ble/util/assign kend 'tput @7 2>/dev/null || tput kend 2>/dev/null' + if [[ $kend == $'\e[5~' ]]; then + ble-bind --csi '1~' insert + ble-bind --csi '2~' home + ble-bind --csi '3~' prior + ble-bind --csi '4~' delete + ble-bind --csi '5~' end + ble-bind --csi '6~' next + else + if [[ $kend == $'\e[F' && ( $TERM == xterm || $TERM == xterm-* || $TERM == kvt ) ]]; then + ble-bind --csi '1~' find + ble-bind --csi '4~' select + else + ble-bind --csi '1~' home + ble-bind --csi '4~' end + fi + ble-bind --csi '2~' insert + ble-bind --csi '3~' delete + ble-bind --csi '5~' prior + ble-bind --csi '6~' next + fi + ble-bind --csi '7~' home + ble-bind --csi '8~' end + local kdch1; ble/util/assign kdch1 'tput kD 2>/dev/null || tput kdch1 2>/dev/null' + [[ $kdch1 == $'\x7F' || $TERM == sun* ]] && ble-bind -k 'DEL' delete + ble-bind --csi '11~' f1 + ble-bind --csi '12~' f2 + ble-bind --csi '13~' f3 + ble-bind --csi '14~' f4 + ble-bind --csi '15~' f5 + ble-bind --csi '17~' f6 + ble-bind --csi '18~' f7 + ble-bind --csi '19~' f8 + ble-bind --csi '20~' f9 + ble-bind --csi '21~' f10 + ble-bind --csi '23~' f11 + ble-bind --csi '24~' f12 + ble-bind --csi '25~' f13 + ble-bind --csi '26~' f14 + ble-bind --csi '28~' f15 + ble-bind --csi '29~' f16 + ble-bind --csi '31~' f17 + ble-bind --csi '32~' f18 + ble-bind --csi '33~' f19 + ble-bind --csi '34~' f20 + ble-bind --csi '200~' paste_begin + ble-bind --csi '201~' paste_end + ble/init:cmap/bind-keypad-key 'SP' SP 3 # kpspace + ble/init:cmap/bind-keypad-key 'A' up 5 + ble/init:cmap/bind-keypad-key 'B' down 5 + ble/init:cmap/bind-keypad-key 'C' right 5 + ble/init:cmap/bind-keypad-key 'D' left 5 + ble/init:cmap/bind-keypad-key 'E' begin 5 + ble/init:cmap/bind-keypad-key 'F' end 5 + ble/init:cmap/bind-keypad-key 'H' home 5 + ble/init:cmap/bind-keypad-key 'I' TAB 3 # kptab (Note: CSI I は xterm SM(?1004) focus と重複) + ble/init:cmap/bind-keypad-key 'M' RET 7 # kpent + ble/init:cmap/bind-keypad-key 'P' f1 5 # kpf1 # Note: 普通の f1-f4 + ble/init:cmap/bind-keypad-key 'Q' f2 5 # kpf2 # に対してこれらの + ble/init:cmap/bind-keypad-key 'R' f3 5 # kpf3 # シーケンスを送る + ble/init:cmap/bind-keypad-key 'S' f4 5 # kpf4 # 端末もある。 + ble/init:cmap/bind-keypad-key 'j' '*' 7 # kpmul + ble/init:cmap/bind-keypad-key 'k' '+' 7 # kpadd + ble/init:cmap/bind-keypad-key 'l' ',' 7 # kpsep + ble/init:cmap/bind-keypad-key 'm' '-' 7 # kpsub + ble/init:cmap/bind-keypad-key 'n' '.' 7 # kpdec + ble/init:cmap/bind-keypad-key 'o' '/' 7 # kpdiv + ble/init:cmap/bind-keypad-key 'p' '0' 7 # kp0 + ble/init:cmap/bind-keypad-key 'q' '1' 7 # kp1 + ble/init:cmap/bind-keypad-key 'r' '2' 7 # kp2 + ble/init:cmap/bind-keypad-key 's' '3' 7 # kp3 + ble/init:cmap/bind-keypad-key 't' '4' 7 # kp4 + ble/init:cmap/bind-keypad-key 'u' '5' 7 # kp5 + ble/init:cmap/bind-keypad-key 'v' '6' 7 # kp6 + ble/init:cmap/bind-keypad-key 'w' '7' 7 # kp7 + ble/init:cmap/bind-keypad-key 'x' '8' 7 # kp8 + ble/init:cmap/bind-keypad-key 'y' '9' 7 # kp9 + ble/init:cmap/bind-keypad-key 'X' '=' 7 # kpeq + ble/init:cmap/bind-keypad-key 'I' focus 4 # Note: 1 (= SS3) は TAB と重複するので設定しない + ble/init:cmap/bind-keypad-key 'O' blur 5 + ble/init:cmap/bind-single-csi 'Z' S-TAB + ble/init:cmap/bind-single-ss3 'a' C-up + ble/init:cmap/bind-single-csi 'a' S-up + ble/init:cmap/bind-single-ss3 'b' C-down + ble/init:cmap/bind-single-csi 'b' S-down + ble/init:cmap/bind-single-ss3 'c' C-right + ble/init:cmap/bind-single-csi 'c' S-right + ble/init:cmap/bind-single-ss3 'd' C-left + ble/init:cmap/bind-single-csi 'd' S-left + ble/init:cmap/bind-single-csi '2 $' S-insert # ECMA-48 違反 + ble/init:cmap/bind-single-csi '3 $' S-delete # ECMA-48 違反 + ble/init:cmap/bind-single-csi '5 $' S-prior # ECMA-48 違反 + ble/init:cmap/bind-single-csi '6 $' S-next # ECMA-48 違反 + ble/init:cmap/bind-single-csi '7 $' S-home # ECMA-48 違反 + ble/init:cmap/bind-single-csi '8 $' S-end # ECMA-48 違反 + ble/init:cmap/bind-single-csi '2 3 $' S-f11 # ECMA-48 違反 + ble/init:cmap/bind-single-csi '2 4 $' S-f12 # ECMA-48 違反 + ble/init:cmap/bind-single-csi '2 5 $' S-f13 # ECMA-48 違反 + ble/init:cmap/bind-single-csi '2 6 $' S-f14 # ECMA-48 違反 + ble/init:cmap/bind-single-csi '2 8 $' S-f15 # ECMA-48 違反 + ble/init:cmap/bind-single-csi '2 9 $' S-f16 # ECMA-48 違反 + ble/init:cmap/bind-single-csi '3 1 $' S-f17 # ECMA-48 違反 + ble/init:cmap/bind-single-csi '3 2 $' S-f18 # ECMA-48 違反 + ble/init:cmap/bind-single-csi '3 3 $' S-f19 # ECMA-48 違反 + ble/init:cmap/bind-single-csi '3 4 $' S-f20 # ECMA-48 違反 + ble/init:cmap/bind-single-csi '[ A' f1 + ble/init:cmap/bind-single-csi '[ B' f2 + ble/init:cmap/bind-single-csi '[ C' f3 + ble/init:cmap/bind-single-csi '[ D' f4 + ble/init:cmap/bind-single-csi '[ E' f5 + ble/init:cmap/bind-single-csi '2 4 7 z' insert + ble/init:cmap/bind-single-csi '2 1 4 z' home + ble/init:cmap/bind-single-csi '2 2 0 z' end + ble/init:cmap/bind-single-csi '2 2 2 z' prior + ble/init:cmap/bind-single-csi '2 1 6 z' next + ble/init:cmap/bind-single-csi '2 2 4 z' f1 + ble/init:cmap/bind-single-csi '2 2 5 z' f2 + ble/init:cmap/bind-single-csi '2 2 6 z' f3 + ble/init:cmap/bind-single-csi '2 2 7 z' f4 + ble/init:cmap/bind-single-csi '2 2 8 z' f5 + ble/init:cmap/bind-single-csi '2 2 9 z' f6 + ble/init:cmap/bind-single-csi '2 3 0 z' f7 + ble/init:cmap/bind-single-csi '2 3 1 z' f8 + ble/init:cmap/bind-single-csi '2 3 2 z' f9 + ble/init:cmap/bind-single-csi '2 3 3 z' f10 + ble/init:cmap/bind-single-csi '2 3 4 z' f11 + ble/init:cmap/bind-single-csi '2 3 5 z' f12 + ble/init:cmap/bind-single-csi '1 z' find # from xterm ctlseqs + ble/init:cmap/bind-single-csi '4 z' select # from xterm ctlseqs + ble/init:cmap/bind-single-csi '2 J' S-home + ble/init:cmap/bind-single-csi 'J' C-end + ble/init:cmap/bind-single-csi 'K' S-end + ble/init:cmap/bind-single-csi '4 l' S-insert + ble/init:cmap/bind-single-csi 'L' C-insert + ble/init:cmap/bind-single-csi '4 h' insert + ble/init:cmap/bind-single-csi '2 K' S-delete + ble/init:cmap/bind-single-csi 'P' delete + _ble_decode_csimap_kitty_u=( + [57358]=capslock [57359]=scrolllock [57360]=numlock [57361]=print [57362]=pause [57363]=menu + [57376]=f13 [57377]=f14 [57378]=f15 [57379]=f16 [57380]=f17 [57381]=f18 [57382]=f19 [57383]=f20 + [57384]=f21 [57385]=f22 [57386]=f23 [57387]=f24 [57388]=f25 [57389]=f26 [57390]=f27 [57391]=f28 + [57392]=f29 [57393]=f30 [57394]=f31 [57395]=f32 [57396]=f33 [57397]=f34 [57398]=f35 + [57399]=0 [57400]=1 [57401]=2 [57402]=3 [57403]=4 [57404]=5 [57405]=6 [57406]=7 [57407]=8 [57408]=9 + [57409]='.' [57410]='/' [57411]='*' [57412]='-' [57413]='+' [57414]=RET [57415]='=' [57416]=',' + [57417]=left [57418]=right [57419]=up [57420]=down + [57421]=prior [57422]=next [57423]=home [57424]=end [57425]=insert [57426]=delete [57427]=begin + [57428]=media_play [57429]=media_pause [57430]=media_play_pause [57431]=media_reverse + [57432]=media_stop [57433]=media_fast_forward [57434]=media_rewind [57435]=media_track_next + [57436]=media_track_prev [57437]=media_record [57438]=lower_volume [57439]=raise_volume + [57440]=mute_volume + [57441]=lshift [57442]=lcontrol [57443]=lalter [57444]=lsuper [57445]=lhyper [57446]=lmeta + [57447]=rshift [57448]=rcontrol [57449]=ralter [57450]=rsuper [57451]=rhyper [57452]=rmeta + [57453]=iso_shift3 [57454]=iso_shift5 + ) + local keyname + for keyname in "${_ble_decode_csimap_kitty_u[@]}"; do + ble-decode-kbd/generate-keycode "$keyname" + done + ble/edit/info/immediate-show text "ble/lib/init-cmap.sh: updating key sequences... done" +} +ble/init:cmap/initialize diff --git a/.local/src/blesh/lib/init-msys1.sh b/.local/src/blesh/lib/init-msys1.sh new file mode 100644 index 0000000..596ef8f --- /dev/null +++ b/.local/src/blesh/lib/init-msys1.sh @@ -0,0 +1,130 @@ +# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license +function ble-edit/io:msys1/is-msys1 { + local cr; cr=$'\r' + [[ $OSTYPE == msys && ! $cr ]] +} +function ble-edit/io:msys1/get-winpid.proc { + /usr/bin/ps | /usr/bin/gawk -v pid="$1" ' + BEGIN { + cygpid_len = 9; + winpid_len = 36; + } + NR == 1 { + line = $0; + if (!match(line, /.*\yPID\y/)) next; + cygpid_end = RLENGTH; + if (!match(line, /.*\yWINPID\y/)) next; + winpid_end = RLENGTH; + next; + } + function get_last_number(line, limit, _, head, i) { + head = substr(line, 1, limit); + if (i = match(head, /[0-9]+$/)) + return substr(head, i, RLENGTH); + return -1; + } + { + cygpid = get_last_number($0, cygpid_end); + if (cygpid != pid) next; + print get_last_number($0, winpid_end); + exit + } + ' +} +function ble-edit/io:msys1/compile-helper { + local helper=$1 + [[ -x $helper && -s $helper && $helper -nt $_ble_base/lib/init-msys1.sh ]] && return 0 + gcc -O2 -s -o "$helper" -xc - << EOF || return 1 +// For MSYS 1.0 +#include <stdio.h> +#include <windows.h> +#include <sys/stat.h> +#include <signal.h> + +BOOL is_process_alive(HANDLE handle) { + DWORD result; + return GetExitCodeProcess(handle, &result) && result == STILL_ACTIVE; +} + +BOOL is_file(const char* filename) { + struct stat st; + return stat(filename, &st) == 0 && S_ISREG(st.st_mode); +} + +int main(int argc, char** argv) { + const char* winpid = argv[1]; + const char* fname_buff = argv[2]; + const char* fname_read = argv[3]; + + signal(SIGINT, SIG_IGN); + //signal(SIGQUIT, SIG_IGN); + + int ppid = atoi(winpid); + if (!ppid) { + fprintf(stderr, "ble.sh (msys1): invalid process ID '%s'\n", winpid); + return 1; + } + HANDLE parent_process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ppid); + if (parent_process == NULL) { + fprintf(stderr, "ble.sh (msys1): failed to open the parent process '%s'\n", winpid); + return 1; + } + + int exit_code = 0; + BOOL terminate = FALSE; + while (!terminate) { + unlink(fname_read); + if (rename(fname_buff, fname_read) != 0) { + perror("ble.sh (msys1)"); + fprintf(stderr, "ble.sh (msys1): failed to move the file '%s' -> '%s'\n", fname_buff, fname_read); + terminate = TRUE; + exit_code = 1; + break; + } + + FILE* f = fopen(fname_read, "r"); + if (!f) { + fprintf(stderr, "ble.sh (msys1): failed to open the file '%s'\n", fname_read); + terminate = TRUE; + exit_code = 1; + break; + } + + for (;;) { + if (!is_process_alive(parent_process)) { + terminate = TRUE; + break; + } + if (is_file(fname_buff)) break; + + int count = 0; + char buff[4096]; + while (count = fread(&buff, 1, sizeof buff, f)) + fwrite(buff, 1, count, stdout); + fflush(stdout); + Sleep(20); + } + fclose(f); + } + + CloseHandle(parent_process); + return exit_code; +} +EOF + [[ -x $helper ]] +} +function ble-edit/io:msys1/start-background { + local basename=$_ble_edit_io_fname2 + local fname_buff=$basename.buff + ble-edit/io:msys1/is-msys1 || return 1 + local helper=$_ble_base_cache/init-msys1-helper.exe + local helper2=$_ble_base_run/$$.init-msys1-helper.exe + ble-edit/io:msys1/compile-helper "$helper" && + /usr/bin/cp "$helper" "$helper2" || return 1 + local winpid + ble/util/assign winpid 'ble-edit/io:msys1/get-winpid.proc $$' + [[ $winpid ]] || return 1 + : >| "$fname_buff" + ble/fd#alloc _ble_edit_io_fd2 '> "$fname_buff"' + "$helper2" "$winpid" "$fname_buff" "${fname_buff%.buff}.read" | ble-edit/io/check-ignoreeof-loop & disown +} &>/dev/null diff --git a/.local/src/blesh/lib/init-term.sh b/.local/src/blesh/lib/init-term.sh new file mode 100644 index 0000000..cd9647b --- /dev/null +++ b/.local/src/blesh/lib/init-term.sh @@ -0,0 +1,228 @@ +# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license +_ble_term_tput= +function ble/init:term/tput { return 1; } +if ble/bin/.freeze-utility-path tput; then + ble/bin/tput cuu 1 &>/dev/null && _ble_term_tput=${_ble_term_tput}i + ble/bin/tput UP 1 &>/dev/null && _ble_term_tput=${_ble_term_tput}c + if [[ $_ble_term_tput ]]; then + function ble/init:term/tput { + local type=$_ble_term_tput + if [[ $1 == -c ]]; then # termcap 優先 + shift + [[ $type == ic ]] && type=c + fi + if [[ $type != c ]]; then + ble/bin/tput "${1%%:*}" "${@:2}" 2>/dev/null + else + ble/bin/tput "${1#*:}" "${@:2}" 2>/dev/null + fi + } + fi +fi +function ble/init:term/register-varname { + local name=$1 + varnames[${#varnames[@]}]=$name +} +function ble/init:term/define-cap { + local IFS=$_ble_term_IFS + local name=$1 def=$2 + shift 2 + ble/util/assign "$name" "ble/init:term/tput $* || ble/util/put \"\$def\"" + ble/init:term/register-varname "$name" +} +function ble/init:term/define-cap.2 { + local IFS=$_ble_term_IFS + local name=$1 def=$2 + shift 2 + ble/util/assign "$name" "ble/util/put x; ble/init:term/tput $* || ble/util/put \"\$def\"; ble/util/put x" + builtin eval "$name=\${$name#x}; $name=\${$name%x}" + ble/init:term/register-varname "$name" +} +_ble_term_sgr_term2ansi=() +ble/init:term/register-varname _ble_term_sgr_term2ansi +_ble_term_rex_sgr=$'\e''\[([0-9;:]+)m' +function ble/init:term/define-sgr-param { + local name=$1 seq=$2 ansi=$3 + if [[ $seq =~ $_ble_term_rex_sgr ]]; then + local rematch1=${BASH_REMATCH[1]} + builtin eval "$name=\$rematch1" + if [[ $ansi ]]; then + local rex='^[0-9]+$' + [[ $rematch1 =~ $rex ]] && + [[ ! ${_ble_term_sgr_term2ansi[rematch1]} ]] && + _ble_term_sgr_term2ansi[rematch1]=$ansi + fi + else + builtin eval "$name=" + fi + if [[ $name =~ ^[a-zA-Z_][a-zA-Z_0-9]*$ ]]; then + ble/init:term/register-varname "$name" + fi +} +function ble/init:term/initialize { + local -a varnames=() + _ble_term_xenl=1 + [[ $_ble_term_tput ]] && + ! ble/init:term/tput xenl:xn &>/dev/null && + _ble_term_xenl= + [[ $TERM == sun* ]] && _ble_term_xenl= + ble/init:term/register-varname _ble_term_xenl + _ble_term_bce= + [[ $_ble_term_tput ]] && + ble/init:term/tput bce:ut &>/dev/null && + _ble_term_bce=1 + ble/init:term/register-varname _ble_term_bce + _ble_term_it=8 + if [[ $_ble_term_tput ]]; then + ble/util/assign _ble_term_it 'ble/init:term/tput it:it' + _ble_term_it=${_ble_term_it:-8} + fi + ble/init:term/register-varname _ble_term_it + ble/init:term/define-cap.2 _ble_term_ind $'\n' ind:sf # $'\eD' + ble/init:term/define-cap _ble_term_ri '' ri:sr # $'\eM' + ble/init:term/define-cap _ble_term_cr $'\r' cr:cr + if [[ $OSTYPE == msys && ! $_ble_term_CR ]]; then # msys-1.0 + [[ $_ble_term_cr ]] || _ble_term_cr=$'\e[G' + if [[ $TERM == cygwin ]]; then + [[ $_ble_term_ind == $'\eD' ]] && _ble_term_ind=$'\n' + _ble_term_xenl= + fi + fi + ble/init:term/define-cap _ble_term_cuu $'\e[%dA' cuu:UP 123 + ble/init:term/define-cap _ble_term_cud $'\e[%dB' cud:DO 123 + ble/init:term/define-cap _ble_term_cuf $'\e[%dC' cuf:RI 123 + ble/init:term/define-cap _ble_term_cub $'\e[%dD' cub:LE 123 + _ble_term_cuu=${_ble_term_cuu//123/%d} + _ble_term_cud=${_ble_term_cud//123/%d} + _ble_term_cuf=${_ble_term_cuf//123/%d} + _ble_term_cub=${_ble_term_cub//123/%d} + _ble_term_ri_or_cuu1=${_ble_term_ri:-${_ble_term_cuu//'%d'/1}} + ble/init:term/register-varname _ble_term_ri_or_cuu1 + ble/init:term/define-cap _ble_term_cup $'\e[13;35H' cup:cm 12 34 + _ble_term_cup=${_ble_term_cup//13/%l} + _ble_term_cup=${_ble_term_cup//35/%c} + _ble_term_cup=${_ble_term_cup//12/%y} + _ble_term_cup=${_ble_term_cup//34/%x} + ble/init:term/define-cap _ble_term_hpa "$_ble_term_cr${_ble_term_cuf//'%d'/123}" hpa:ch 123 + _ble_term_hpa=${_ble_term_hpa//123/%x} + _ble_term_hpa=${_ble_term_hpa//124/%c} + ble/init:term/define-cap _ble_term_vpa "${_ble_term_cuu//'%d'/199}${_ble_term_cud//'%d'/123}" vpa:cv 123 + _ble_term_vpa=${_ble_term_vpa//123/%y} + _ble_term_vpa=${_ble_term_vpa//124/%l} + ble/init:term/define-cap _ble_term_clear $'\e[H\e[2J' clear:cl + ble/init:term/define-cap _ble_term_il $'\e[%dL' il:AL 123 + ble/init:term/define-cap _ble_term_dl $'\e[%dM' -c dl:DL 123 + _ble_term_il=${_ble_term_il//123/%d} + _ble_term_dl=${_ble_term_dl//123/%d} + ble/init:term/define-cap _ble_term_el $'\e[K' el:ce + ble/init:term/define-cap _ble_term_el1 $'\e[1K' el1:cb + if [[ $_ble_term_el == $'\e[K' && $_ble_term_el1 == $'\e[1K' ]]; then + _ble_term_el2=$'\e[2K' + else + _ble_term_el2=$_ble_term_el1$_ble_term_el + fi + ble/init:term/register-varname _ble_term_el2 + ble/init:term/define-cap _ble_term_ed $'\e[J' -c ed:cd + ble/init:term/define-cap _ble_term_ich '' ich:IC 123 # CSI @ + ble/init:term/define-cap _ble_term_dch '' dch:DC 123 # CSI P + ble/init:term/define-cap _ble_term_ech '' ech:ec 123 # CSI X + _ble_term_ich=${_ble_term_ich//123/%d} + _ble_term_dch=${_ble_term_dch//123/%d} + _ble_term_ech=${_ble_term_ech//123/%d} + ble/init:term/define-cap _ble_term_sc $'\e7' sc:sc # \e[s + ble/init:term/define-cap _ble_term_rc $'\e8' rc:rc # \e[u + [[ $TERM == minix ]] && _ble_term_sc= _ble_term_rc= + ble/init:term/define-cap _ble_term_Ss '' Ss:Ss 123 # DECSCUSR + _ble_term_Ss=${_ble_term_Ss//123/@1} + ble/init:term/define-cap _ble_term_cvvis $'\e[?25h' cvvis:vs + ble/init:term/define-cap _ble_term_civis $'\e[?25l' civis:vi + [[ $TERM == minix ]] && _ble_term_cvvis= _ble_term_civis= + [[ $_ble_term_cvvis == $'\e[?12;25h' || $_ble_term_cvvis == $'\e[?25;12h' ]] && + _ble_term_cvvis=$'\e[?25h' + [[ $_ble_term_cvvis == $'\e[34l'* && $_ble_term_civis != *$'\e[34h'* ]] && + _ble_term_civis=$_ble_term_civis$'\e[34h' + [[ $_ble_term_civis == $'\e[?25l'* && $_ble_term_cvvis != *$'\e[?25h'* ]] && + _ble_term_cvvis=$_ble_term_cvvis$'\e[?25h' + ble/init:term/define-cap _ble_term_smcup '' smcup:ti # \e[?1049h + ble/init:term/define-cap _ble_term_rmcup '' rmcup:te # \e[?1049l + ble/init:term/define-cap _ble_term_tsl '' tsl:ts + ble/init:term/define-cap _ble_term_fsl '' fsl:fs + ble/init:term/define-cap _ble_term_dsl '' dsl:ds + [[ ! $_ble_term_dsl && $_ble_term_fsl ]] && + _ble_term_dsl=$_ble_term_tsl$_ble_term_fsl + ble/init:term/define-cap _ble_term_sgr0 $'\e[m' sgr0:me + ble/init:term/define-cap _ble_term_bold $'\e[1m' bold:md + ble/init:term/define-cap _ble_term_blink $'\e[5m' blink:mb + ble/init:term/define-cap _ble_term_rev $'\e[7m' rev:mr + ble/init:term/define-cap _ble_term_invis $'\e[8m' invis:mk + ble/init:term/define-sgr-param _ble_term_sgr_bold "$_ble_term_bold" 1 + ble/init:term/define-sgr-param _ble_term_sgr_blink "$_ble_term_blink" 5 + ble/init:term/define-sgr-param _ble_term_sgr_rev "$_ble_term_rev" 7 + ble/init:term/define-sgr-param _ble_term_sgr_invis "$_ble_term_invis" 8 + ble/init:term/define-cap _ble_term_sitm $'\e[3m' sitm:ZH + ble/init:term/define-cap _ble_term_ritm $'\e[23m' ritm:ZR + ble/init:term/define-cap _ble_term_smul $'\e[4m' smul:us + ble/init:term/define-cap _ble_term_rmul $'\e[24m' rmul:ue + ble/init:term/define-cap _ble_term_smso $'\e[7m' smso:so + ble/init:term/define-cap _ble_term_rmso $'\e[27m' rmso:se + ble/init:term/define-sgr-param _ble_term_sgr_sitm "$_ble_term_sitm" 3 + ble/init:term/define-sgr-param _ble_term_sgr_ritm "$_ble_term_ritm" 23 + ble/init:term/define-sgr-param _ble_term_sgr_smul "$_ble_term_smul" 4 + ble/init:term/define-sgr-param _ble_term_sgr_rmul "$_ble_term_rmul" 24 + ble/init:term/define-sgr-param _ble_term_sgr_smso "$_ble_term_smso" 7 + ble/init:term/define-sgr-param _ble_term_sgr_rmso "$_ble_term_rmso" 27 + ble/init:term/register-varname _ble_term_sgr_rev_reset + if [[ $_ble_term_sgr_smso && $_ble_term_sgr_smso == "$_ble_term_sgr_rev" ]]; then + _ble_term_sgr_rev_reset=$_ble_term_sgr_rmso + else + _ble_term_sgr_rev_reset= + fi + ble/init:term/define-cap _ble_term_colors 256 colors:Co + local i + _ble_term_setaf=() + _ble_term_setab=() + _ble_term_sgr_af=() + _ble_term_sgr_ab=() + for ((i=0;i<16;i++)); do + local i1=$((i%8)) af= ab= + if [[ $TERM == *-direct ]]; then + if ((i<8)); then + af=$'\e[3'$i'm' + ab=$'\e[4'$i'm' + else + af=$'\e[38;5;'$i'm' + ab=$'\e[48;5;'$i'm' + fi + else + if ((i<_ble_term_colors)); then + local j1 + ((j1=(i1==3?6: + (i1==6?3: + (i1==1?4: + (i1==4?1:i1)))))) + local j=$((i-i1+j1)) + ble/util/assign af 'ble/init:term/tput setaf:AF "$i" 2>/dev/null' + [[ $af ]] || ble/util/assign af 'ble/init:term/tput setf:Sf "$j" 2>/dev/null' + ble/util/assign ab 'ble/init:term/tput setab:AB "$i" 2>/dev/null' + [[ $ab ]] || ble/util/assign ab 'ble/init:term/tput setb:Sb "$j" 2>/dev/null' + fi + fi + [[ $af ]] || af=$'\e[3'$i1'm' + [[ $ab ]] || ab=$'\e[4'$i1'm' + _ble_term_setaf[i]=$af + _ble_term_setab[i]=$ab + local ansi_sgr_af=3$i1 ansi_sgr_ab=4$i1 + ((i>=8)) && ansi_sgr_af=9$i1 ansi_sgr_ab=10$i1 + ble/init:term/define-sgr-param "_ble_term_sgr_af[i]" "$af" "$ansi_sgr_af" + ble/init:term/define-sgr-param "_ble_term_sgr_ab[i]" "$ab" "$ansi_sgr_ab" + done + ble/init:term/register-varname "_ble_term_setaf" + ble/init:term/register-varname "_ble_term_setab" + ble/init:term/register-varname "_ble_term_sgr_af" + ble/init:term/register-varname "_ble_term_sgr_ab" + ble/util/declare-print-definitions "${varnames[@]}" >| "$_ble_base_cache/term.$TERM" +} +ble/util/put "ble/term.sh: updating tput cache for TERM=$TERM... " >&2 +ble/init:term/initialize +ble/util/print $'\r'"ble/term.sh: updating tput cache for TERM=$TERM... done" >&2 +return 0 diff --git a/.local/src/blesh/lib/test-canvas.sh b/.local/src/blesh/lib/test-canvas.sh new file mode 100644 index 0000000..6d329ea --- /dev/null +++ b/.local/src/blesh/lib/test-canvas.sh @@ -0,0 +1,479 @@ +# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license +ble-import lib/core-test +_ble_test_canvas_contra= +if [[ -x ext/contra ]]; then + _ble_test_canvas_contra=ext/contra +elif [[ $(printf 'hello world' | contra test 5 2 2>/dev/null) == $' worl\nd ' ]]; then + _ble_test_canvas_contra=contra +fi +function ble/test:canvas/trace.contra { + [[ $_ble_test_canvas_contra ]] || return 0 # skip + local w=${1%%:*} h=${1#*:} esc=$2 opts=$3 test_opts=$4 + local expect=$(sed 's/\$$//') + local ret x=0 y=0 g=0 rex termw=$w termh=$h + rex=':x=([^:]+):'; [[ :$test_opts: =~ $rex ]] && ((x=BASH_REMATCH[1])) + rex=':y=([^:]+):'; [[ :$test_opts: =~ $rex ]] && ((y=BASH_REMATCH[1])) + rex=':termw=([^:]+):'; [[ :$test_opts: =~ $rex ]] && ((termw=BASH_REMATCH[1])) + rex=':termh=([^:]+):'; [[ :$test_opts: =~ $rex ]] && ((termh=BASH_REMATCH[1])) + local x0=$x y0=$y + LINES=$h COLUMNS=$w ble/canvas/trace "$esc" "$opts" + local out=$ret + ble/string#quote-word "$esc"; local q_esc=$ret + ble/string#quote-word "$opts"; local q_opts=$ret + ble/test --depth=1 --display-code="trace $q_esc $q_opts" \ + '{ printf "\e['$((y0+1))';'$((x0+1))'H"; ble/util/put "$out";} | "$_ble_test_canvas_contra" test "$termw" "$termh"' \ + stdout="$expect" +} +ble/test/start-section 'ble/canvas/trace (relative:confine:measure-bbox)' 17 +ble/test:canvas/trace.contra 10:10 'hello world this is a flow world' relative x=3:y=3:termw=20 << EOF + $ + $ + $ + hello w $ +orld this $ +is a flow $ +world $ + $ + $ + $ +EOF +ble/test:canvas/trace.contra 20:1 '12345678901234567890hello' confine << EOF +12345678901234567890$ +EOF +ble/test:canvas/trace.contra 10:1 $'hello\nworld' confine << EOF +helloworld$ +EOF +ble/test:canvas/trace.contra 10:2 $'hello\nworld check' confine << EOF +hello $ +world chec$ +EOF +ble/test:canvas/trace.contra 10:6 $'hello\e[B\e[4D123' measure-bbox x=3:y=2 << EOF + $ + $ + hello $ + 123 $ + $ + $ +EOF +[[ $_ble_test_canvas_contra ]] && + ble/test 'echo "$x1-$x2:$y1-$y2"' stdout='3-8:2-4' +ble/test:canvas/trace.contra 10:2 日本語 measure-bbox << EOF +日本語 $ + $ +EOF +[[ $_ble_test_canvas_contra ]] && + ble/test 'echo "$x1-$x2:$y1-$y2"' stdout='0-6:0-1' +ble/test:canvas/trace.contra 10:2 $'hello\eDworld' measure-bbox << EOF +hello $ + world$ +EOF +[[ $_ble_test_canvas_contra ]] && + ble/test 'echo "$x1-$x2:$y1-$y2"' stdout='0-10:0-2' +ble/test:canvas/trace.contra 10:2 $'hello\eMworld' measure-bbox << EOF + world$ +hello $ +EOF +[[ $_ble_test_canvas_contra ]] && + ble/test 'echo "$x1-$x2:$y1-$y2"' stdout='0-10:-1-1' +( + LINES=10 COLUMNS=10 _ble_term_xenl=1 + ble/test 'x=0 y=0; ble/canvas/trace "HelloWorld"; ret=$x,$y' ret=10,0 + ble/test 'x=0 y=0; ble/canvas/trace "HelloWorldH"; ret=$x,$y' ret=1,1 + ble/test 'x=0 y=0; ble/canvas/trace "HelloWorldHello"; ret=$x,$y' ret=5,1 + ble/test 'x=0 y=0; ble/canvas/trace "HelloWorldHelloWorldHello"; ret=$x,$y' ret=5,2 + ble/test 'x=0 y=0; ble/canvas/trace "HelloWorldHelloWorldHelloWorldHello"; ret=$x,$y' ret=5,3 +) +ble/test/start-section 'ble/canvas/trace (cfuncs)' 18 +function ble/test:canvas/check-trace-1 { + local input=$1 ex=$2 ey=$3 + ble/canvas/trace.draw "$input" + ble/test --depth=1 '((x==ex&&y==ey))' +} +function ble/test:canvas/check-trace { + local -a DRAW_BUFF=() + ble/canvas/put.draw "$_ble_term_clear" + local x=0 y=0 + ble/test:canvas/check-trace-1 "abc" 3 0 + ble/test:canvas/check-trace-1 $'\n\n\nn' 1 3 + ble/test:canvas/check-trace-1 $'\e[3BB' 2 6 + ble/test:canvas/check-trace-1 $'\e[2AA' 3 4 + ble/test:canvas/check-trace-1 $'\e[20CC' 24 4 + ble/test:canvas/check-trace-1 $'\e[8DD' 17 4 + ble/test:canvas/check-trace-1 $'\e[9EE' 1 13 + ble/test:canvas/check-trace-1 $'\e[6FF' 1 7 + ble/test:canvas/check-trace-1 $'\e[28GG' 28 7 + ble/test:canvas/check-trace-1 $'\e[II' 33 7 + ble/test:canvas/check-trace-1 $'\e[3ZZ' 17 7 + ble/test:canvas/check-trace-1 $'\eDD' 18 8 + ble/test:canvas/check-trace-1 $'\eMM' 19 7 + ble/test:canvas/check-trace-1 $'\e77\e[3;3Hexcur\e8\e[C8' 21 7 + ble/test:canvas/check-trace-1 $'\eEE' 1 8 + ble/test:canvas/check-trace-1 $'\e[10;24HH' 24 9 + ble/test:canvas/check-trace-1 $'\e[1;94mb\e[m' 25 9 + local expect=$(sed 's/\$$//' << EOF +abc $ + $ + excur $ +n $ + A D C $ + $ + B $ +F Z M78 G I $ +E D $ + Hb $ + $ + $ + $ +E $ + $ +EOF +) + [[ $_ble_test_canvas_contra ]] && + ble/test --depth=1 \ + 'ble/canvas/flush.draw | $_ble_test_canvas_contra test 40 15' \ + stdout="$expect" +} +ble/test:canvas/check-trace +ble/test/start-section 'ble/canvas/trace (justify)' 24 +ble/test:canvas/trace.contra 30:1 'a b c' justify << EOF +a b c$ +EOF +ble/test:canvas/trace.contra 30:1 ' center ' justify << EOF + center $ +EOF +ble/test:canvas/trace.contra 30:1 ' right-aligned' justify << EOF + right-aligned$ +EOF +ble/test:canvas/trace.contra 30:1 'left-aligned' justify << EOF +left-aligned $ +EOF +ble/test:canvas/trace.contra 30:1 ' 日本語' justify << EOF + 日本語$ +EOF +ble/test:canvas/trace.contra 30:1 'a b c d e f' justify << EOF +a b c d e f$ +EOF +ble/test:canvas/trace.contra 30:2 $'hello center world\na b c d e f' justify << EOF +hello center world$ +a b c d e f$ +EOF +ble/test:canvas/trace.contra 30:3 'A brown fox jumped over the lazy dog. A brown fox jumped over the lazy dog.' justify << EOF +A brown fox jumped over the la$ +zy dog. A brown fox jumped ove$ +r the lazy dog.$ +EOF +ble/test:canvas/trace.contra 30:2 $'hello blesh world\rHELLO WORLD\nhello world HELLO BLESH WORLD' justify=$' \r' << EOF +hello blesh worldHELLO WORLD$ +hello world HELLO BLESH WORLD$ +EOF +COLUMNS=10 LINES=10 x=3 y=2 ble/canvas/trace $'a b c\n' justify:measure-bbox +ble/test 'echo "$x1,$y1:$x2,$y2"' stdout:'0,2:10,4' +COLUMNS=10 LINES=10 x=3 y=2 ble/canvas/trace $' hello ' justify:measure-bbox +ble/test 'echo "$x1,$y1:$x2,$y2"' stdout:'2,2:7,3' +ble/test:canvas/trace.contra 30:1 $'\e[3Dhello\rblesh\rworld\e[1D' justify=$'\r' x=5 << EOF +hello blesh world$ +EOF +ble/test:canvas/trace.contra \ + 30:5 $'hello world\nfoo bar buzz\nA quick brown fox\nLorem ipsum\n1 1 2 3 5 8 13 21 34 55 89 144' \ + justify:clip=2,1+24,5 << EOF +o bar $ + quick brown $ +rem i $ +1 2 3 5 8 13 21 34 55 89 $ + $ +EOF +ble/test:canvas/trace.contra 30:1 $'hello1 world long long word quick brown' justify:confine << EOF +hello1 world long long word qu$ +EOF +ble/test:canvas/trace.contra 30:1 $'hello2 world long long word quick brown' justify:truncate << EOF +hello2 world long long word qu$ +EOF +ble/test:canvas/trace.contra 60:2 $'-- INSERT --\r/home/murase\r2021-01-01 00:00:00' justify << EOF +-- INSERT 2021-01-01 00:00:00$ + $ +EOF +ble/test:canvas/trace.contra 30:3 $'hello\r\vquick check\v\rtest \e[2Afoo\r\vbar' justify:truncate << EOF +hello foo$ +quick check bar$ + test $ +EOF +ble/test:canvas/trace.contra 30:3 $'hello\n2021-01-01\nA' right:measure-bbox:measure-gbox << EOF + hello$ + 2021-01-01$ + A$ +EOF +if [[ $_ble_test_canvas_contra ]]; then + ble/test 'echo "bbox:$x1,$y1-$x2,$y2"' stdout='bbox:0,0-30,3' + ble/test 'echo "gbox:$gx1,$gy1-$gx2,$gy2"' stdout='gbox:20,0-30,3' +fi +ble/test:canvas/trace.contra 30:3 $'hello\n2021-01-01\nA' center:measure-bbox:measure-gbox << EOF + hello $ + 2021-01-01 $ + A $ +EOF +if [[ $_ble_test_canvas_contra ]]; then + ble/test 'echo "bbox:$x1,$y1-$x2,$y2"' stdout='bbox:0,0-20,3' + ble/test 'echo "gbox:$gx1,$gy1-$gx2,$gy2"' stdout='gbox:10,0-20,3' +fi +ble/test:canvas/trace.contra 10:1 $'xyz\e[4Daxyz' relative:measure-bbox x=3 << EOF + axyz $ +EOF +if [[ $_ble_test_canvas_contra ]]; then + ble/test 'echo "bbox:$x1,$y1-$x2,$y2"' stdout='bbox:2,0-6,1' +fi +ble/test/start-section 'ble/canvas/trace-text' 11 +( + sgr0= sgr1= + lines=1 cols=10 _ble_term_xenl=1 x=0 y=0 + ble/test 'ble/canvas/trace-text "Hello World";ret="$x,$y,$ret"' ret='10,0,Hello Worl' + lines=1 cols=10 _ble_term_xenl= x=0 y=0 + ble/test 'ble/canvas/trace-text "Hello World";ret="$x,$y,$ret"' ret='9,0,Hello Wor' + lines=1 cols=10 _ble_term_xenl=1 x=3 y=0 + ble/test 'ble/canvas/trace-text "Hello World";ret="$x,$y,$ret"' ret='10,0,Hello W' + lines=3 cols=10 _ble_term_xenl=1 x=3 y=0 + ble/test 'ble/canvas/trace-text "Hello Bash World";ret="$x,$y,$ret"' ret='9,1,Hello Bash World' + lines=3 cols=10 _ble_term_xenl=1 x=3 y=0 + ble/test 'ble/canvas/trace-text "これは日本語の文章";ret="$x,$y,$ret"' ret=$'2,2,これは\n日本語の文章' + lines=3 cols=10 _ble_term_xenl=1 x=3 y=0 + ble/test 'ble/canvas/trace-text "これは日本語の文章" nonewline;ret="$x,$y,$ret"' ret='2,2,これは 日本語の文章' + lines=3 cols=10 _ble_term_xenl=1 x=0 y=0 + ble/test 'ble/canvas/trace-text "これは日本";ret="$x,$y,$ret"' ret=$'0,1,これは日本\n' + lines=3 cols=10 _ble_term_xenl=0 x=0 y=0 + ble/test 'ble/canvas/trace-text "これは日本";ret="$x,$y,$ret"' ret=$'0,1,これは日本' + lines=3 cols=10 _ble_term_xenl=1 x=0 y=0 + ble/test 'ble/canvas/trace-text "これは日本" nonewline;ret="$x,$y,$ret"' ret=$'10,0,これは日本' + lines=3 cols=10 _ble_term_xenl=0 x=0 y=0 + ble/test 'ble/canvas/trace-text "これは日本" nonewline;ret="$x,$y,$ret"' ret=$'0,1,これは日本' + lines=1 cols=12 _ble_term_xenl=1 x=0 y=0 + ble/test $'ble/canvas/trace-text "あ\nい\nう" external-sgr;ret="$x,$y,$ret"' ret=$'10,0,あ^Jい^Jう' +) +ble/test/end-section +ble/test/start-section 'ble/textmap#update' 5 +function ble/test:canvas/textmap { + local text=$1 + x=0 y=0 + _ble_textmap_length= + _ble_textmap_pos=() + _ble_textmap_glyph=() + _ble_textmap_ichg=() + _ble_textmap_dbeg=0 + _ble_textmap_dend=${#text} + _ble_textmap_dend0=0 + ble/textmap#update "$text" + [[ :$opts: == *:stderr:* ]] && + declare -p _ble_textmap_pos >&2 +} +( + ble/test:canvas/textmap $'hello\nworld\ncheck' + ble/test 'ble/textmap#getxy.out 5; ret=$x,$y' ret='5,0' + ble/test 'ble/textmap#getxy.out 6; ret=$x,$y' ret='0,1' + ble/test 'ble/textmap#getxy.out 11; ret=$x,$y' ret='5,1' + ble/test 'ble/textmap#getxy.out 12; ret=$x,$y' ret='0,2' + ble/test 'ble/textmap#getxy.out 17; ret=$x,$y' ret='5,2' +) +ble/test/start-section 'ble/unicode/GraphemeCluster/c2break' 72 +( + bleopt emoji_opts=ri:tpvs:epvs:zwj + ble/test 'ble/unicode/GraphemeCluster/c2break $((0x20))' ret="$_ble_unicode_GraphemeClusterBreak_Other" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0x41))' ret="$_ble_unicode_GraphemeClusterBreak_Other" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0x7E))' ret="$_ble_unicode_GraphemeClusterBreak_Other" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0x00))' ret="$_ble_unicode_GraphemeClusterBreak_Control" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0x0d))' ret="$_ble_unicode_GraphemeClusterBreak_Control" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0x0a))' ret="$_ble_unicode_GraphemeClusterBreak_Control" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0x1F))' ret="$_ble_unicode_GraphemeClusterBreak_Control" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0x80))' ret="$_ble_unicode_GraphemeClusterBreak_Control" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0x9F))' ret="$_ble_unicode_GraphemeClusterBreak_Control" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0x0308))' ret="$_ble_unicode_GraphemeClusterBreak_Extend" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0x200C))' ret="$_ble_unicode_GraphemeClusterBreak_Extend" # ZWNJ + ble/test 'ble/unicode/GraphemeCluster/c2break $((0x200D))' ret="$_ble_unicode_GraphemeClusterBreak_ZWJ" # ZWJ + ble/test 'ble/unicode/GraphemeCluster/c2break $((0x0600))' ret="$_ble_unicode_GraphemeClusterBreak_Prepend" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0x0605))' ret="$_ble_unicode_GraphemeClusterBreak_Prepend" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0x06DD))' ret="$_ble_unicode_GraphemeClusterBreak_Prepend" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0x110BD))' ret="$_ble_unicode_GraphemeClusterBreak_Prepend" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0xE33))' ret="$_ble_unicode_GraphemeClusterBreak_SpacingMark" # THAI CHARACTER SARA AM + ble/test 'ble/unicode/GraphemeCluster/c2break $((0xEB3))' ret="$_ble_unicode_GraphemeClusterBreak_SpacingMark" # LAO VOWEL SIGN AM + ble/test 'ble/unicode/GraphemeCluster/c2break $((0x1100))' ret="$_ble_unicode_GraphemeClusterBreak_L" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0x115F))' ret="$_ble_unicode_GraphemeClusterBreak_L" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0xA960))' ret="$_ble_unicode_GraphemeClusterBreak_L" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0xA97C))' ret="$_ble_unicode_GraphemeClusterBreak_L" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0x1160))' ret="$_ble_unicode_GraphemeClusterBreak_V" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0x11A2))' ret="$_ble_unicode_GraphemeClusterBreak_V" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0xD7B0))' ret="$_ble_unicode_GraphemeClusterBreak_V" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0xD7C6))' ret="$_ble_unicode_GraphemeClusterBreak_V" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0x11A8))' ret="$_ble_unicode_GraphemeClusterBreak_T" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0x11F9))' ret="$_ble_unicode_GraphemeClusterBreak_T" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0xD7CB))' ret="$_ble_unicode_GraphemeClusterBreak_T" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0xD7FB))' ret="$_ble_unicode_GraphemeClusterBreak_T" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0xAC00))' ret="$_ble_unicode_GraphemeClusterBreak_LV" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0xAC1C))' ret="$_ble_unicode_GraphemeClusterBreak_LV" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0xAC38))' ret="$_ble_unicode_GraphemeClusterBreak_LV" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0xAC01))' ret="$_ble_unicode_GraphemeClusterBreak_LVT" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0xAC04))' ret="$_ble_unicode_GraphemeClusterBreak_LVT" + ble/test 'ble/unicode/GraphemeCluster/c2break $((0x1F1E6))' ret="$_ble_unicode_GraphemeClusterBreak_Regional_Indicator" # RI A + ble/test 'ble/unicode/GraphemeCluster/c2break $((0x1F1FF))' ret="$_ble_unicode_GraphemeClusterBreak_Regional_Indicator" # RI Z + ble/test 'ble/unicode/GraphemeCluster/c2break $((0x1F32B))' ret="$_ble_unicode_GraphemeClusterBreak_Pictographic" + if ((_ble_bash>=40200)); then + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "\U1F1E6\U1F1FF\U1F1E6\U1F1FF" 1' ret="0" + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "\U1F1E6\U1F1FF\U1F1E6\U1F1FF" 2' ret="0" + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "\U1F1E6\U1F1FF\U1F1E6\U1F1FF" 3' ret="2" + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "\U1F1E6\U1F1FF\U1F1E6\U1F1FF" 4' ret="2" + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "\U1F1E6\U1F1FF\U1F1E6\U1F1FF" 5' ret="4" + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "A\U1F1E6\U1F1FF\U1F1E6\U1F1FF\U1F1E6" 2' ret=1 + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "A\U1F1E6\U1F1FF\U1F1E6\U1F1FF\U1F1E6" 3' ret=1 + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "A\U1F1E6\U1F1FF\U1F1E6\U1F1FF\U1F1E6" 4' ret=3 + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "A\U1F1E6\U1F1FF\U1F1E6\U1F1FF\U1F1E6" 5' ret=3 + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "A\U1F1E6\U1F1FF\U1F1E6\U1F1FF\U1F1E6" 6' ret=5 + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "A\U1F1E6\U1F1FF\U1F1E6\U1F1FF\U1F1E6" 7' ret=6 + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "A\U1F1E6\U1F1FF\U1F1E6\U1F1FF\U1F1E6Z" 7' ret=6 + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "A\u600\u600\u600\u600\U1F1E6\U1F1FF" 7' ret=1 + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "A\u600\u600\u600\u600\U1F1E6\U1F1FF" 6' ret=1 + ble/test $'bleopt_grapheme_cluster=legacy ble/unicode/GraphemeCluster/find-previous-boundary "A\u600\u600\u600\u600\U1F1E6\U1F1FF" 7' ret=5 + ble/test $'bleopt_grapheme_cluster=legacy ble/unicode/GraphemeCluster/find-previous-boundary "A\u600\u600\u600\u600\U1F1E6\U1F1FF" 6' ret=5 + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "\U1F636\U200D\U1F32B\UFE0F" 1' ret=0 + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "\U1F636\U200D\U1F32B\UFE0F" 2' ret=0 + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "\U1F636\U200D\U1F32B\UFE0F" 3' ret=0 + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "\U1F636\U200D\U1F32B\UFE0F" 4' ret=0 + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "\U1F636\U200D\U1F32B\UFE0F" 5' ret=4 + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "a\U1F636\U200D\U1F32B\UFE0F" 2' ret=1 + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "a\U1F636\U200D\U1F32B\UFE0F" 3' ret=1 + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "a\U1F636\U200D\U1F32B\UFE0F" 4' ret=1 + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "a\U1F636\U200D\U1F32B\UFE0F" 5' ret=1 + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "a\U1F636\U200D\U1F32B\UFE0F" 6' ret=5 + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "a\U200D\U1F32B\UFE0F" 2' ret=0 + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "a\U200D\U1F32B\UFE0F" 3' ret=2 + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "a\U200D\U1F32B\UFE0F" 4' ret=2 + ble/test $'ble/unicode/GraphemeCluster/find-previous-boundary "a\U200D\U1F32B\UFE0F" 5' ret=4 + ble/test "ble/test:canvas/textmap \$'@@' stderr; ble/textmap#get-index-at -v ret 1 0" ret=1 + ble/test "ble/test:canvas/textmap \$'@\u0308@' stderr; ble/textmap#get-index-at -v ret 1 0" ret=2 + ble/test "ble/test:canvas/textmap \$'@\u0308\u0308@' stderr; ble/textmap#get-index-at -v ret 1 0" ret=3 + ble/test "ble/test:canvas/textmap \$'@\u0308\u0308\u0308@' stderr; ble/textmap#get-index-at -v ret 1 0" ret=4 + fi +) +ble/test/start-section 'ble/unicode/GraphemeCluster/c2break (GraphemeBreakTest.txt)' 3251 +( + bleopt emoji_opts=ri:tpvs:epvs:zwj + tests_cases=( + 0,1,2:'\U0020\U0020' 0,0,2,3:'\U0020\U0308\U0020' 0,1,2:'\U0020\U000D' 0,0,2,3:'\U0020\U0308\U000D' 0,1,2:'\U0020\U000A' 0,0,2,3:'\U0020\U0308\U000A' + 0,1,2:'\U0020\U0001' 0,0,2,3:'\U0020\U0308\U0001' 0,0,2:'\U0020\U034F' 0,0,0,3:'\U0020\U0308\U034F' 0,1,2:'\U0020\U1F1E6' 0,0,2,3:'\U0020\U0308\U1F1E6' + 0,1,2:'\U0020\U0600' 0,0,2,3:'\U0020\U0308\U0600' 0,0,2:'\U0020\U0903' 0,0,0,3:'\U0020\U0308\U0903' 0,1,2:'\U0020\U1100' 0,0,2,3:'\U0020\U0308\U1100' + 0,1,2:'\U0020\U1160' 0,0,2,3:'\U0020\U0308\U1160' 0,1,2:'\U0020\U11A8' 0,0,2,3:'\U0020\U0308\U11A8' 0,1,2:'\U0020\UAC00' 0,0,2,3:'\U0020\U0308\UAC00' + 0,1,2:'\U0020\UAC01' 0,0,2,3:'\U0020\U0308\UAC01' 0,1,2:'\U0020\U231A' 0,0,2,3:'\U0020\U0308\U231A' 0,0,2:'\U0020\U0300' 0,0,0,3:'\U0020\U0308\U0300' + 0,0,2:'\U0020\U200D' 0,0,0,3:'\U0020\U0308\U200D' 0,1,2:'\U0020\U0378' 0,0,2,3:'\U0020\U0308\U0378' 0,1,2:'\U000D\U0020' 0,1,2,3:'\U000D\U0308\U0020' + 0,1,2:'\U000D\U000D' 0,1,2,3:'\U000D\U0308\U000D' 0,1,2:'\U000D\U000A' 0,1,2,3:'\U000D\U0308\U000A' 0,1,2:'\U000D\U0001' 0,1,2,3:'\U000D\U0308\U0001' + 0,1,2:'\U000D\U034F' 0,1,1,3:'\U000D\U0308\U034F' 0,1,2:'\U000D\U1F1E6' 0,1,2,3:'\U000D\U0308\U1F1E6' 0,1,2:'\U000D\U0600' 0,1,2,3:'\U000D\U0308\U0600' + 0,1,2:'\U000D\U0903' 0,1,1,3:'\U000D\U0308\U0903' 0,1,2:'\U000D\U1100' 0,1,2,3:'\U000D\U0308\U1100' 0,1,2:'\U000D\U1160' 0,1,2,3:'\U000D\U0308\U1160' + 0,1,2:'\U000D\U11A8' 0,1,2,3:'\U000D\U0308\U11A8' 0,1,2:'\U000D\UAC00' 0,1,2,3:'\U000D\U0308\UAC00' 0,1,2:'\U000D\UAC01' 0,1,2,3:'\U000D\U0308\UAC01' + 0,1,2:'\U000D\U231A' 0,1,2,3:'\U000D\U0308\U231A' 0,1,2:'\U000D\U0300' 0,1,1,3:'\U000D\U0308\U0300' 0,1,2:'\U000D\U200D' 0,1,1,3:'\U000D\U0308\U200D' + 0,1,2:'\U000D\U0378' 0,1,2,3:'\U000D\U0308\U0378' 0,1,2:'\U000A\U0020' 0,1,2,3:'\U000A\U0308\U0020' 0,1,2:'\U000A\U000D' 0,1,2,3:'\U000A\U0308\U000D' + 0,1,2:'\U000A\U000A' 0,1,2,3:'\U000A\U0308\U000A' 0,1,2:'\U000A\U0001' 0,1,2,3:'\U000A\U0308\U0001' 0,1,2:'\U000A\U034F' 0,1,1,3:'\U000A\U0308\U034F' + 0,1,2:'\U000A\U1F1E6' 0,1,2,3:'\U000A\U0308\U1F1E6' 0,1,2:'\U000A\U0600' 0,1,2,3:'\U000A\U0308\U0600' 0,1,2:'\U000A\U0903' 0,1,1,3:'\U000A\U0308\U0903' + 0,1,2:'\U000A\U1100' 0,1,2,3:'\U000A\U0308\U1100' 0,1,2:'\U000A\U1160' 0,1,2,3:'\U000A\U0308\U1160' 0,1,2:'\U000A\U11A8' 0,1,2,3:'\U000A\U0308\U11A8' + 0,1,2:'\U000A\UAC00' 0,1,2,3:'\U000A\U0308\UAC00' 0,1,2:'\U000A\UAC01' 0,1,2,3:'\U000A\U0308\UAC01' 0,1,2:'\U000A\U231A' 0,1,2,3:'\U000A\U0308\U231A' + 0,1,2:'\U000A\U0300' 0,1,1,3:'\U000A\U0308\U0300' 0,1,2:'\U000A\U200D' 0,1,1,3:'\U000A\U0308\U200D' 0,1,2:'\U000A\U0378' 0,1,2,3:'\U000A\U0308\U0378' + 0,1,2:'\U0001\U0020' 0,1,2,3:'\U0001\U0308\U0020' 0,1,2:'\U0001\U000D' 0,1,2,3:'\U0001\U0308\U000D' 0,1,2:'\U0001\U000A' 0,1,2,3:'\U0001\U0308\U000A' + 0,1,2:'\U0001\U0001' 0,1,2,3:'\U0001\U0308\U0001' 0,1,2:'\U0001\U034F' 0,1,1,3:'\U0001\U0308\U034F' 0,1,2:'\U0001\U1F1E6' 0,1,2,3:'\U0001\U0308\U1F1E6' + 0,1,2:'\U0001\U0600' 0,1,2,3:'\U0001\U0308\U0600' 0,1,2:'\U0001\U0903' 0,1,1,3:'\U0001\U0308\U0903' 0,1,2:'\U0001\U1100' 0,1,2,3:'\U0001\U0308\U1100' + 0,1,2:'\U0001\U1160' 0,1,2,3:'\U0001\U0308\U1160' 0,1,2:'\U0001\U11A8' 0,1,2,3:'\U0001\U0308\U11A8' 0,1,2:'\U0001\UAC00' 0,1,2,3:'\U0001\U0308\UAC00' + 0,1,2:'\U0001\UAC01' 0,1,2,3:'\U0001\U0308\UAC01' 0,1,2:'\U0001\U231A' 0,1,2,3:'\U0001\U0308\U231A' 0,1,2:'\U0001\U0300' 0,1,1,3:'\U0001\U0308\U0300' + 0,1,2:'\U0001\U200D' 0,1,1,3:'\U0001\U0308\U200D' 0,1,2:'\U0001\U0378' 0,1,2,3:'\U0001\U0308\U0378' 0,1,2:'\U034F\U0020' 0,0,2,3:'\U034F\U0308\U0020' + 0,1,2:'\U034F\U000D' 0,0,2,3:'\U034F\U0308\U000D' 0,1,2:'\U034F\U000A' 0,0,2,3:'\U034F\U0308\U000A' 0,1,2:'\U034F\U0001' 0,0,2,3:'\U034F\U0308\U0001' + 0,0,2:'\U034F\U034F' 0,0,0,3:'\U034F\U0308\U034F' 0,1,2:'\U034F\U1F1E6' 0,0,2,3:'\U034F\U0308\U1F1E6' 0,1,2:'\U034F\U0600' 0,0,2,3:'\U034F\U0308\U0600' + 0,0,2:'\U034F\U0903' 0,0,0,3:'\U034F\U0308\U0903' 0,1,2:'\U034F\U1100' 0,0,2,3:'\U034F\U0308\U1100' 0,1,2:'\U034F\U1160' 0,0,2,3:'\U034F\U0308\U1160' + 0,1,2:'\U034F\U11A8' 0,0,2,3:'\U034F\U0308\U11A8' 0,1,2:'\U034F\UAC00' 0,0,2,3:'\U034F\U0308\UAC00' 0,1,2:'\U034F\UAC01' 0,0,2,3:'\U034F\U0308\UAC01' + 0,1,2:'\U034F\U231A' 0,0,2,3:'\U034F\U0308\U231A' 0,0,2:'\U034F\U0300' 0,0,0,3:'\U034F\U0308\U0300' 0,0,2:'\U034F\U200D' 0,0,0,3:'\U034F\U0308\U200D' + 0,1,2:'\U034F\U0378' 0,0,2,3:'\U034F\U0308\U0378' 0,1,2:'\U1F1E6\U0020' 0,0,2,3:'\U1F1E6\U0308\U0020' 0,1,2:'\U1F1E6\U000D' 0,0,2,3:'\U1F1E6\U0308\U000D' + 0,1,2:'\U1F1E6\U000A' 0,0,2,3:'\U1F1E6\U0308\U000A' 0,1,2:'\U1F1E6\U0001' 0,0,2,3:'\U1F1E6\U0308\U0001' 0,0,2:'\U1F1E6\U034F' 0,0,0,3:'\U1F1E6\U0308\U034F' + 0,0,2:'\U1F1E6\U1F1E6' 0,0,2,3:'\U1F1E6\U0308\U1F1E6' 0,1,2:'\U1F1E6\U0600' 0,0,2,3:'\U1F1E6\U0308\U0600' 0,0,2:'\U1F1E6\U0903' + 0,0,0,3:'\U1F1E6\U0308\U0903' 0,1,2:'\U1F1E6\U1100' 0,0,2,3:'\U1F1E6\U0308\U1100' 0,1,2:'\U1F1E6\U1160' 0,0,2,3:'\U1F1E6\U0308\U1160' 0,1,2:'\U1F1E6\U11A8' + 0,0,2,3:'\U1F1E6\U0308\U11A8' 0,1,2:'\U1F1E6\UAC00' 0,0,2,3:'\U1F1E6\U0308\UAC00' 0,1,2:'\U1F1E6\UAC01' 0,0,2,3:'\U1F1E6\U0308\UAC01' 0,1,2:'\U1F1E6\U231A' + 0,0,2,3:'\U1F1E6\U0308\U231A' 0,0,2:'\U1F1E6\U0300' 0,0,0,3:'\U1F1E6\U0308\U0300' 0,0,2:'\U1F1E6\U200D' 0,0,0,3:'\U1F1E6\U0308\U200D' 0,1,2:'\U1F1E6\U0378' + 0,0,2,3:'\U1F1E6\U0308\U0378' 0,0,2:'\U0600\U0020' 0,0,2,3:'\U0600\U0308\U0020' 0,1,2:'\U0600\U000D' 0,0,2,3:'\U0600\U0308\U000D' 0,1,2:'\U0600\U000A' + 0,0,2,3:'\U0600\U0308\U000A' 0,1,2:'\U0600\U0001' 0,0,2,3:'\U0600\U0308\U0001' 0,0,2:'\U0600\U034F' 0,0,0,3:'\U0600\U0308\U034F' 0,0,2:'\U0600\U1F1E6' + 0,0,2,3:'\U0600\U0308\U1F1E6' 0,0,2:'\U0600\U0600' 0,0,2,3:'\U0600\U0308\U0600' 0,0,2:'\U0600\U0903' 0,0,0,3:'\U0600\U0308\U0903' 0,0,2:'\U0600\U1100' + 0,0,2,3:'\U0600\U0308\U1100' 0,0,2:'\U0600\U1160' 0,0,2,3:'\U0600\U0308\U1160' 0,0,2:'\U0600\U11A8' 0,0,2,3:'\U0600\U0308\U11A8' 0,0,2:'\U0600\UAC00' + 0,0,2,3:'\U0600\U0308\UAC00' 0,0,2:'\U0600\UAC01' 0,0,2,3:'\U0600\U0308\UAC01' 0,0,2:'\U0600\U231A' 0,0,2,3:'\U0600\U0308\U231A' 0,0,2:'\U0600\U0300' + 0,0,0,3:'\U0600\U0308\U0300' 0,0,2:'\U0600\U200D' 0,0,0,3:'\U0600\U0308\U200D' 0,0,2:'\U0600\U0378' 0,0,2,3:'\U0600\U0308\U0378' 0,1,2:'\U0903\U0020' + 0,0,2,3:'\U0903\U0308\U0020' 0,1,2:'\U0903\U000D' 0,0,2,3:'\U0903\U0308\U000D' 0,1,2:'\U0903\U000A' 0,0,2,3:'\U0903\U0308\U000A' 0,1,2:'\U0903\U0001' + 0,0,2,3:'\U0903\U0308\U0001' 0,0,2:'\U0903\U034F' 0,0,0,3:'\U0903\U0308\U034F' 0,1,2:'\U0903\U1F1E6' 0,0,2,3:'\U0903\U0308\U1F1E6' 0,1,2:'\U0903\U0600' + 0,0,2,3:'\U0903\U0308\U0600' 0,0,2:'\U0903\U0903' 0,0,0,3:'\U0903\U0308\U0903' 0,1,2:'\U0903\U1100' 0,0,2,3:'\U0903\U0308\U1100' 0,1,2:'\U0903\U1160' + 0,0,2,3:'\U0903\U0308\U1160' 0,1,2:'\U0903\U11A8' 0,0,2,3:'\U0903\U0308\U11A8' 0,1,2:'\U0903\UAC00' 0,0,2,3:'\U0903\U0308\UAC00' 0,1,2:'\U0903\UAC01' + 0,0,2,3:'\U0903\U0308\UAC01' 0,1,2:'\U0903\U231A' 0,0,2,3:'\U0903\U0308\U231A' 0,0,2:'\U0903\U0300' 0,0,0,3:'\U0903\U0308\U0300' 0,0,2:'\U0903\U200D' + 0,0,0,3:'\U0903\U0308\U200D' 0,1,2:'\U0903\U0378' 0,0,2,3:'\U0903\U0308\U0378' 0,1,2:'\U1100\U0020' 0,0,2,3:'\U1100\U0308\U0020' 0,1,2:'\U1100\U000D' + 0,0,2,3:'\U1100\U0308\U000D' 0,1,2:'\U1100\U000A' 0,0,2,3:'\U1100\U0308\U000A' 0,1,2:'\U1100\U0001' 0,0,2,3:'\U1100\U0308\U0001' 0,0,2:'\U1100\U034F' + 0,0,0,3:'\U1100\U0308\U034F' 0,1,2:'\U1100\U1F1E6' 0,0,2,3:'\U1100\U0308\U1F1E6' 0,1,2:'\U1100\U0600' 0,0,2,3:'\U1100\U0308\U0600' 0,0,2:'\U1100\U0903' + 0,0,0,3:'\U1100\U0308\U0903' 0,0,2:'\U1100\U1100' 0,0,2,3:'\U1100\U0308\U1100' 0,0,2:'\U1100\U1160' 0,0,2,3:'\U1100\U0308\U1160' 0,1,2:'\U1100\U11A8' + 0,0,2,3:'\U1100\U0308\U11A8' 0,0,2:'\U1100\UAC00' 0,0,2,3:'\U1100\U0308\UAC00' 0,0,2:'\U1100\UAC01' 0,0,2,3:'\U1100\U0308\UAC01' 0,1,2:'\U1100\U231A' + 0,0,2,3:'\U1100\U0308\U231A' 0,0,2:'\U1100\U0300' 0,0,0,3:'\U1100\U0308\U0300' 0,0,2:'\U1100\U200D' 0,0,0,3:'\U1100\U0308\U200D' 0,1,2:'\U1100\U0378' + 0,0,2,3:'\U1100\U0308\U0378' 0,1,2:'\U1160\U0020' 0,0,2,3:'\U1160\U0308\U0020' 0,1,2:'\U1160\U000D' 0,0,2,3:'\U1160\U0308\U000D' 0,1,2:'\U1160\U000A' + 0,0,2,3:'\U1160\U0308\U000A' 0,1,2:'\U1160\U0001' 0,0,2,3:'\U1160\U0308\U0001' 0,0,2:'\U1160\U034F' 0,0,0,3:'\U1160\U0308\U034F' 0,1,2:'\U1160\U1F1E6' + 0,0,2,3:'\U1160\U0308\U1F1E6' 0,1,2:'\U1160\U0600' 0,0,2,3:'\U1160\U0308\U0600' 0,0,2:'\U1160\U0903' 0,0,0,3:'\U1160\U0308\U0903' 0,1,2:'\U1160\U1100' + 0,0,2,3:'\U1160\U0308\U1100' 0,0,2:'\U1160\U1160' 0,0,2,3:'\U1160\U0308\U1160' 0,0,2:'\U1160\U11A8' 0,0,2,3:'\U1160\U0308\U11A8' 0,1,2:'\U1160\UAC00' + 0,0,2,3:'\U1160\U0308\UAC00' 0,1,2:'\U1160\UAC01' 0,0,2,3:'\U1160\U0308\UAC01' 0,1,2:'\U1160\U231A' 0,0,2,3:'\U1160\U0308\U231A' 0,0,2:'\U1160\U0300' + 0,0,0,3:'\U1160\U0308\U0300' 0,0,2:'\U1160\U200D' 0,0,0,3:'\U1160\U0308\U200D' 0,1,2:'\U1160\U0378' 0,0,2,3:'\U1160\U0308\U0378' 0,1,2:'\U11A8\U0020' + 0,0,2,3:'\U11A8\U0308\U0020' 0,1,2:'\U11A8\U000D' 0,0,2,3:'\U11A8\U0308\U000D' 0,1,2:'\U11A8\U000A' 0,0,2,3:'\U11A8\U0308\U000A' 0,1,2:'\U11A8\U0001' + 0,0,2,3:'\U11A8\U0308\U0001' 0,0,2:'\U11A8\U034F' 0,0,0,3:'\U11A8\U0308\U034F' 0,1,2:'\U11A8\U1F1E6' 0,0,2,3:'\U11A8\U0308\U1F1E6' 0,1,2:'\U11A8\U0600' + 0,0,2,3:'\U11A8\U0308\U0600' 0,0,2:'\U11A8\U0903' 0,0,0,3:'\U11A8\U0308\U0903' 0,1,2:'\U11A8\U1100' 0,0,2,3:'\U11A8\U0308\U1100' 0,1,2:'\U11A8\U1160' + 0,0,2,3:'\U11A8\U0308\U1160' 0,0,2:'\U11A8\U11A8' 0,0,2,3:'\U11A8\U0308\U11A8' 0,1,2:'\U11A8\UAC00' 0,0,2,3:'\U11A8\U0308\UAC00' 0,1,2:'\U11A8\UAC01' + 0,0,2,3:'\U11A8\U0308\UAC01' 0,1,2:'\U11A8\U231A' 0,0,2,3:'\U11A8\U0308\U231A' 0,0,2:'\U11A8\U0300' 0,0,0,3:'\U11A8\U0308\U0300' 0,0,2:'\U11A8\U200D' + 0,0,0,3:'\U11A8\U0308\U200D' 0,1,2:'\U11A8\U0378' 0,0,2,3:'\U11A8\U0308\U0378' 0,1,2:'\UAC00\U0020' 0,0,2,3:'\UAC00\U0308\U0020' 0,1,2:'\UAC00\U000D' + 0,0,2,3:'\UAC00\U0308\U000D' 0,1,2:'\UAC00\U000A' 0,0,2,3:'\UAC00\U0308\U000A' 0,1,2:'\UAC00\U0001' 0,0,2,3:'\UAC00\U0308\U0001' 0,0,2:'\UAC00\U034F' + 0,0,0,3:'\UAC00\U0308\U034F' 0,1,2:'\UAC00\U1F1E6' 0,0,2,3:'\UAC00\U0308\U1F1E6' 0,1,2:'\UAC00\U0600' 0,0,2,3:'\UAC00\U0308\U0600' 0,0,2:'\UAC00\U0903' + 0,0,0,3:'\UAC00\U0308\U0903' 0,1,2:'\UAC00\U1100' 0,0,2,3:'\UAC00\U0308\U1100' 0,0,2:'\UAC00\U1160' 0,0,2,3:'\UAC00\U0308\U1160' 0,0,2:'\UAC00\U11A8' + 0,0,2,3:'\UAC00\U0308\U11A8' 0,1,2:'\UAC00\UAC00' 0,0,2,3:'\UAC00\U0308\UAC00' 0,1,2:'\UAC00\UAC01' 0,0,2,3:'\UAC00\U0308\UAC01' 0,1,2:'\UAC00\U231A' + 0,0,2,3:'\UAC00\U0308\U231A' 0,0,2:'\UAC00\U0300' 0,0,0,3:'\UAC00\U0308\U0300' 0,0,2:'\UAC00\U200D' 0,0,0,3:'\UAC00\U0308\U200D' 0,1,2:'\UAC00\U0378' + 0,0,2,3:'\UAC00\U0308\U0378' 0,1,2:'\UAC01\U0020' 0,0,2,3:'\UAC01\U0308\U0020' 0,1,2:'\UAC01\U000D' 0,0,2,3:'\UAC01\U0308\U000D' 0,1,2:'\UAC01\U000A' + 0,0,2,3:'\UAC01\U0308\U000A' 0,1,2:'\UAC01\U0001' 0,0,2,3:'\UAC01\U0308\U0001' 0,0,2:'\UAC01\U034F' 0,0,0,3:'\UAC01\U0308\U034F' 0,1,2:'\UAC01\U1F1E6' + 0,0,2,3:'\UAC01\U0308\U1F1E6' 0,1,2:'\UAC01\U0600' 0,0,2,3:'\UAC01\U0308\U0600' 0,0,2:'\UAC01\U0903' 0,0,0,3:'\UAC01\U0308\U0903' 0,1,2:'\UAC01\U1100' + 0,0,2,3:'\UAC01\U0308\U1100' 0,1,2:'\UAC01\U1160' 0,0,2,3:'\UAC01\U0308\U1160' 0,0,2:'\UAC01\U11A8' 0,0,2,3:'\UAC01\U0308\U11A8' 0,1,2:'\UAC01\UAC00' + 0,0,2,3:'\UAC01\U0308\UAC00' 0,1,2:'\UAC01\UAC01' 0,0,2,3:'\UAC01\U0308\UAC01' 0,1,2:'\UAC01\U231A' 0,0,2,3:'\UAC01\U0308\U231A' 0,0,2:'\UAC01\U0300' + 0,0,0,3:'\UAC01\U0308\U0300' 0,0,2:'\UAC01\U200D' 0,0,0,3:'\UAC01\U0308\U200D' 0,1,2:'\UAC01\U0378' 0,0,2,3:'\UAC01\U0308\U0378' 0,1,2:'\U231A\U0020' + 0,0,2,3:'\U231A\U0308\U0020' 0,1,2:'\U231A\U000D' 0,0,2,3:'\U231A\U0308\U000D' 0,1,2:'\U231A\U000A' 0,0,2,3:'\U231A\U0308\U000A' 0,1,2:'\U231A\U0001' + 0,0,2,3:'\U231A\U0308\U0001' 0,0,2:'\U231A\U034F' 0,0,0,3:'\U231A\U0308\U034F' 0,1,2:'\U231A\U1F1E6' 0,0,2,3:'\U231A\U0308\U1F1E6' 0,1,2:'\U231A\U0600' + 0,0,2,3:'\U231A\U0308\U0600' 0,0,2:'\U231A\U0903' 0,0,0,3:'\U231A\U0308\U0903' 0,1,2:'\U231A\U1100' 0,0,2,3:'\U231A\U0308\U1100' 0,1,2:'\U231A\U1160' + 0,0,2,3:'\U231A\U0308\U1160' 0,1,2:'\U231A\U11A8' 0,0,2,3:'\U231A\U0308\U11A8' 0,1,2:'\U231A\UAC00' 0,0,2,3:'\U231A\U0308\UAC00' 0,1,2:'\U231A\UAC01' + 0,0,2,3:'\U231A\U0308\UAC01' 0,1,2:'\U231A\U231A' 0,0,2,3:'\U231A\U0308\U231A' 0,0,2:'\U231A\U0300' 0,0,0,3:'\U231A\U0308\U0300' 0,0,2:'\U231A\U200D' + 0,0,0,3:'\U231A\U0308\U200D' 0,1,2:'\U231A\U0378' 0,0,2,3:'\U231A\U0308\U0378' 0,1,2:'\U0300\U0020' 0,0,2,3:'\U0300\U0308\U0020' 0,1,2:'\U0300\U000D' + 0,0,2,3:'\U0300\U0308\U000D' 0,1,2:'\U0300\U000A' 0,0,2,3:'\U0300\U0308\U000A' 0,1,2:'\U0300\U0001' 0,0,2,3:'\U0300\U0308\U0001' 0,0,2:'\U0300\U034F' + 0,0,0,3:'\U0300\U0308\U034F' 0,1,2:'\U0300\U1F1E6' 0,0,2,3:'\U0300\U0308\U1F1E6' 0,1,2:'\U0300\U0600' 0,0,2,3:'\U0300\U0308\U0600' 0,0,2:'\U0300\U0903' + 0,0,0,3:'\U0300\U0308\U0903' 0,1,2:'\U0300\U1100' 0,0,2,3:'\U0300\U0308\U1100' 0,1,2:'\U0300\U1160' 0,0,2,3:'\U0300\U0308\U1160' 0,1,2:'\U0300\U11A8' + 0,0,2,3:'\U0300\U0308\U11A8' 0,1,2:'\U0300\UAC00' 0,0,2,3:'\U0300\U0308\UAC00' 0,1,2:'\U0300\UAC01' 0,0,2,3:'\U0300\U0308\UAC01' 0,1,2:'\U0300\U231A' + 0,0,2,3:'\U0300\U0308\U231A' 0,0,2:'\U0300\U0300' 0,0,0,3:'\U0300\U0308\U0300' 0,0,2:'\U0300\U200D' 0,0,0,3:'\U0300\U0308\U200D' 0,1,2:'\U0300\U0378' + 0,0,2,3:'\U0300\U0308\U0378' 0,1,2:'\U200D\U0020' 0,0,2,3:'\U200D\U0308\U0020' 0,1,2:'\U200D\U000D' 0,0,2,3:'\U200D\U0308\U000D' 0,1,2:'\U200D\U000A' + 0,0,2,3:'\U200D\U0308\U000A' 0,1,2:'\U200D\U0001' 0,0,2,3:'\U200D\U0308\U0001' 0,0,2:'\U200D\U034F' 0,0,0,3:'\U200D\U0308\U034F' 0,1,2:'\U200D\U1F1E6' + 0,0,2,3:'\U200D\U0308\U1F1E6' 0,1,2:'\U200D\U0600' 0,0,2,3:'\U200D\U0308\U0600' 0,0,2:'\U200D\U0903' 0,0,0,3:'\U200D\U0308\U0903' 0,1,2:'\U200D\U1100' + 0,0,2,3:'\U200D\U0308\U1100' 0,1,2:'\U200D\U1160' 0,0,2,3:'\U200D\U0308\U1160' 0,1,2:'\U200D\U11A8' 0,0,2,3:'\U200D\U0308\U11A8' 0,1,2:'\U200D\UAC00' + 0,0,2,3:'\U200D\U0308\UAC00' 0,1,2:'\U200D\UAC01' 0,0,2,3:'\U200D\U0308\UAC01' 0,1,2:'\U200D\U231A' 0,0,2,3:'\U200D\U0308\U231A' 0,0,2:'\U200D\U0300' + 0,0,0,3:'\U200D\U0308\U0300' 0,0,2:'\U200D\U200D' 0,0,0,3:'\U200D\U0308\U200D' 0,1,2:'\U200D\U0378' 0,0,2,3:'\U200D\U0308\U0378' 0,1,2:'\U0378\U0020' + 0,0,2,3:'\U0378\U0308\U0020' 0,1,2:'\U0378\U000D' 0,0,2,3:'\U0378\U0308\U000D' 0,1,2:'\U0378\U000A' 0,0,2,3:'\U0378\U0308\U000A' 0,1,2:'\U0378\U0001' + 0,0,2,3:'\U0378\U0308\U0001' 0,0,2:'\U0378\U034F' 0,0,0,3:'\U0378\U0308\U034F' 0,1,2:'\U0378\U1F1E6' 0,0,2,3:'\U0378\U0308\U1F1E6' 0,1,2:'\U0378\U0600' + 0,0,2,3:'\U0378\U0308\U0600' 0,0,2:'\U0378\U0903' 0,0,0,3:'\U0378\U0308\U0903' 0,1,2:'\U0378\U1100' 0,0,2,3:'\U0378\U0308\U1100' 0,1,2:'\U0378\U1160' + 0,0,2,3:'\U0378\U0308\U1160' 0,1,2:'\U0378\U11A8' 0,0,2,3:'\U0378\U0308\U11A8' 0,1,2:'\U0378\UAC00' 0,0,2,3:'\U0378\U0308\UAC00' 0,1,2:'\U0378\UAC01' + 0,0,2,3:'\U0378\U0308\UAC01' 0,1,2:'\U0378\U231A' 0,0,2,3:'\U0378\U0308\U231A' 0,0,2:'\U0378\U0300' 0,0,0,3:'\U0378\U0308\U0300' 0,0,2:'\U0378\U200D' + 0,0,0,3:'\U0378\U0308\U200D' 0,1,2:'\U0378\U0378' 0,0,2,3:'\U0378\U0308\U0378' 0,1,2,3,4,5:'\U000D\U000A\U0061\U000A\U0308' 0,0,2:'\U0061\U0308' + 0,0,2,3:'\U0020\U200D\U0646' 0,0,2,3:'\U0646\U200D\U0020' 0,0,2:'\U1100\U1100' 0,0,2,3:'\UAC00\U11A8\U1100' 0,0,2,3:'\UAC01\U11A8\U1100' + 0,0,2,3,4:'\U1F1E6\U1F1E7\U1F1E8\U0062' 0,1,1,3,4,5:'\U0061\U1F1E6\U1F1E7\U1F1E8\U0062' 0,1,1,1,4,5,6:'\U0061\U1F1E6\U1F1E7\U200D\U1F1E8\U0062' + 0,1,1,3,3,5,6:'\U0061\U1F1E6\U200D\U1F1E7\U1F1E8\U0062' 0,1,1,3,3,5,6:'\U0061\U1F1E6\U1F1E7\U1F1E8\U1F1E9\U0062' 0,0,2:'\U0061\U200D' + 0,0,2,3:'\U0061\U0308\U0062' 0,0,2,3:'\U0061\U0903\U0062' 0,1,1,3:'\U0061\U0600\U0062' 0,0,2,3:'\U1F476\U1F3FF\U1F476' 0,0,2,3:'\U0061\U1F3FF\U1F476' + 0,0,2,2,2,5:'\U0061\U1F3FF\U1F476\U200D\U1F6D1' 0,0,0,0,0,0,6:'\U1F476\U1F3FF\U0308\U200D\U1F476\U1F3FF' 0,0,0,3:'\U1F6D1\U200D\U1F6D1' + 0,0,2,3:'\U0061\U200D\U1F6D1' 0,0,0,3:'\U2701\U200D\U2701' 0,0,2,3:'\U0061\U200D\U2701' + ) + function ble/test:canvas/GraphemeClusterBreak/find-previous-boundary { + local ans=${1%%:*} str=${1#*:} + ble/string#split ans , "$ans" + local i=0 b=0 + for k in "${!ans[@]}"; do + ble/test "ble/unicode/GraphemeCluster/find-previous-boundary \$'$str' $((k+1))" ret=${ans[k]} + if ((ans[k]>b)); then + local ret= c= w= cs= extend= + ble/test "ble/unicode/GraphemeCluster/match \$'$str' $b && ((ret=b+1+extend))" ret=${ans[k]} + ((b=ans[k])) + fi + done + } + if ((_ble_bash>=40200)); then + for spec in "${tests_cases[@]}"; do + ble/test:canvas/GraphemeClusterBreak/find-previous-boundary "$spec" + done + fi +) +ble/test/end-section diff --git a/.local/src/blesh/lib/test-complete.sh b/.local/src/blesh/lib/test-complete.sh new file mode 100644 index 0000000..cd7c0e1 --- /dev/null +++ b/.local/src/blesh/lib/test-complete.sh @@ -0,0 +1,28 @@ +# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license +ble-import lib/core-complete +ble-import lib/core-test +ble/test/start-section 'ble/complete' 7 +( + function _collect { + local text=${args[1]} p0=0 i out= + for ((i=0;i<${#ret[@]};i++)); do + ((p=ret[i])) + if ((i%2==0)); then + out=$out${text:p0:p-p0}'[' + else + out=$out${text:p0:p-p0}']' + fi + p0=$p + done + ((p0<${#text})) && out=$out${text:p0} + ret=$out + } + ble/test 'args=(akf Makefile 0); ble/complete/candidates/filter:hsubseq/match "${args[@]}"; _collect' ret='M[ak]e[f]ile' + ble/test 'args=(akf Makefile 1); ble/complete/candidates/filter:hsubseq/match "${args[@]}"; _collect' ret='Makefile' + ble/test 'args=(Mkf Makefile 1); ble/complete/candidates/filter:hsubseq/match "${args[@]}"; _collect' ret='[M]a[k]e[f]ile' + ble/test 'args=(Maf Makefile 1); ble/complete/candidates/filter:hsubseq/match "${args[@]}"; _collect' ret='[Ma]ke[f]ile' + ble/test 'args=(Mak Makefile 1); ble/complete/candidates/filter:hsubseq/match "${args[@]}"; _collect' ret='[Mak]efile' + ble/test 'args=(ake Makefile 0); ble/complete/candidates/filter:hsubseq/match "${args[@]}"; _collect' ret='M[ake]file' + ble/test 'args=(afe Makefile 0); ble/complete/candidates/filter:hsubseq/match "${args[@]}"; _collect' ret='M[a]ke[f]il[e]' +) +ble/test/end-section diff --git a/.local/src/blesh/lib/test-decode.sh b/.local/src/blesh/lib/test-decode.sh new file mode 100644 index 0000000..712b218 --- /dev/null +++ b/.local/src/blesh/lib/test-decode.sh @@ -0,0 +1,39 @@ +# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license +ble-import lib/core-test +ble/test/start-section 'ble/decode' 33 +( + ble/test 'ble/builtin/bind/.parse-keyname tab ; ret=${chars[0]}' ret=9 + ble/test 'ble/builtin/bind/.parse-keyname TAB ; ret=${chars[0]}' ret=9 + ble/test 'ble/builtin/bind/.parse-keyname newline; ret=${chars[0]}' ret=10 + ble/test 'ble/builtin/bind/.parse-keyname LFD ; ret=${chars[0]}' ret=10 + ble/test 'ble/builtin/bind/.parse-keyname Return ; ret=${chars[0]}' ret=13 + ble/test 'ble/builtin/bind/.parse-keyname RET ; ret=${chars[0]}' ret=13 + ble/test 'ble/builtin/bind/.parse-keyname Space ; ret=${chars[0]}' ret=32 + ble/test 'ble/builtin/bind/.parse-keyname SPC ; ret=${chars[0]}' ret=32 + ble/test 'ble/builtin/bind/.parse-keyname Rubout ; ret=${chars[0]}' ret=127 + ble/test 'ble/builtin/bind/.parse-keyname DEL ; ret=${chars[0]}' ret=127 + ble/test 'ble/builtin/bind/.parse-keyname Escape ; ret=${chars[0]}' ret=27 + ble/test 'ble/builtin/bind/.parse-keyname ESC ; ret=${chars[0]}' ret=27 + ble/test 'ble/builtin/bind/.parse-keyname C-Space; ret=${chars[0]}' ret=0 + ble/test 'ble/builtin/bind/.parse-keyname s ; ret=${chars[0]}' ret=115 + ble/test 'ble/builtin/bind/.parse-keyname S ; ret=${chars[0]}' ret=83 + ble/test "ble/builtin/bind/.parse-keyname '\C-x\C-y' ; ret=\${chars[0]}" ret=25 # C-y + ble/test "ble/builtin/bind/.parse-keyname 'xyz' ; ret=\${chars[0]}" ret=120 # x + ble/test "ble/builtin/bind/.parse-keyname '\a' ; ret=\${chars[0]}" ret=92 # \ (backslash) + ble/test "ble/builtin/bind/.parse-keyname '\C-nop' ; ret=\${chars[0]}" ret=14 # C-n + ble/test "ble/builtin/bind/.parse-keyname '\C-xC-y' ; ret=\${chars[0]}" ret=25 # C-y + ble/test "ble/builtin/bind/.parse-keyname '\C-axC-b' ; ret=\${chars[0]}" ret=2 # C-b + ble/test "ble/builtin/bind/.parse-keyname 'helloC-b' ; ret=\${chars[0]}" ret=2 # C-b + ble/test "ble/builtin/bind/.parse-keyname 'helloC-x,TAB' ; ret=\${chars[0]}" ret=24 # C-x + ble/test "ble/builtin/bind/.parse-keyname 'C-xTAB' ; ret=\${chars[0]}" ret=24 # C-x + ble/test "ble/builtin/bind/.parse-keyname 'TABC-x' ; ret=\${chars[0]}" ret=24 # C-x + ble/test "ble/builtin/bind/.parse-keyname 'BC-' ; ret=\${chars[0]}" ret=0 # C-@ + ble/test "ble/builtin/bind/.parse-keyname 'C-M-a' ; ret=\${chars[0]}" ret=129 # C-M-a + ble/test "ble/builtin/bind/.parse-keyname 'M-C-a' ; ret=\${chars[0]}" ret=129 # C-M-a + ble/test "ble/builtin/bind/.parse-keyname 'C-aalpha-beta'; ret=\${chars[0]}" ret=2 # C-b + ble/test "ble/builtin/bind/.parse-keyname '\C-a\M-c' ; ret=\${chars[0]}" ret=131 # C-M-c + ble/test "ble/builtin/bind/.parse-keyname 'panic-trim-c' ; ret=\${chars[0]}" ret=131 # C-M-c + ble/test "ble/builtin/bind/.parse-keyname 'C--' ; ret=\${chars[0]}" ret=0 # C-@ + ble/test "ble/builtin/bind/.parse-keyname 'C--x' ; ret=\${chars[0]}" ret=24 # C-x +) +ble/test/end-section diff --git a/.local/src/blesh/lib/test-edit.sh b/.local/src/blesh/lib/test-edit.sh new file mode 100644 index 0000000..f9d8211 --- /dev/null +++ b/.local/src/blesh/lib/test-edit.sh @@ -0,0 +1,8 @@ +# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license +ble-import lib/core-test +ble/test/start-section 'ble/edit' 2 +( + ble/test "_ble_edit_str=$'echo\nhello\nworld' ble-edit/content/find-logical-eol 13 -1" exit=0 ret=10 + ble/test "_ble_edit_str=$'echo\nhello\nworld' ble-edit/content/find-logical-bol 13 -1" exit=0 ret=5 +) +ble/test/end-section diff --git a/.local/src/blesh/lib/test-main.sh b/.local/src/blesh/lib/test-main.sh new file mode 100644 index 0000000..dc6cb57 --- /dev/null +++ b/.local/src/blesh/lib/test-main.sh @@ -0,0 +1,79 @@ +# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license +ble-import lib/core-test +ble/test/start-section 'ble/main' 19 +( + ble/test ble/util/put a stdout=a + ble/test ble/util/print a stdout=a + ble/test 'ble/util/put "a b"' stdout='a b' + ble/test 'ble/util/print "a b"' stdout='a b' + ble/test 'ble/util/put "a b"; ble/util/put "c d"' \ + stdout='a bc d' + ble/test 'ble/util/print "a b"; ble/util/print "c d"' \ + stdout='a b' \ + stdout='c d' +) +( + function ble/test/dummy-1 { true; } + function ble/test/dummy-2 { true; } + function ble/test/dummy-3 { true; } + ble/test ble/bin#has ble/test/dummy-1 + ble/test ble/bin#has ble/test/dummy-{1..3} + ble/test ble/bin#has ble/test/dummy-0 exit=1 + ble/test ble/bin#has ble/test/dummy-{0..2} exit=1 +) +( + ble/bin/.freeze-utility-path readlink ls + function ble/test:readlink.impl1 { + ret=$1 + ble/util/readlink/.resolve-loop + } + function ble/test:readlink.impl2 { + ret=$1 + ble/function#push ble/bin/readlink + ble/util/readlink/.resolve-loop + ble/function#pop ble/bin/readlink + } + ble/test/chdir + mkdir -p ab/cd/ef + touch ab/cd/ef/file.txt + ln -s ef/file.txt ab/cd/link1 + ln -s ab link.d + ln -s link.d/cd/link1 f.txt + ble/test ' + ble/util/readlink f.txt + [[ $ret != /* ]] && ret=${PWD%/}/$ret' \ + ret="${PWD%/}/ab/cd/ef/file.txt" + ln -s loop1.sh loop0.sh + ln -s loop2.sh loop1.sh + ln -s loop3.sh loop2.sh + ln -s loop1.sh loop3.sh + for impl in impl1 impl2; do + ble/test "ble/test:readlink.$impl loop0.sh" ret='loop1.sh' + done + mkdir -p phys.dir + touch phys.dir/1.txt + ln -s ../../../phys.dir ab/cd/ef/phys.link + ln -s ab/cd/ef/phys.link phys.link + local pwd=$PWD xpath= + ble/test code:' + path=phys.link/1.txt + ble/util/readlink/.resolve-physical-directory + declare -p path PWD >&2 + [[ $path == */phys.dir/1.txt && $PWD == "$pwd" ]]' + ble/test/rmdir +) +( + ble/test '[[ -d $_ble_base ]]' + ble/test '[[ -d $_ble_base_run ]]' + ble/test '[[ -d $_ble_base_cache ]]' +) +( + qnl="\$'\n'" + value=$'\nxxx is a function\nhello\nyyy is a function\n' + pattern=$'\n+([][{}:[:alnum:]]) is a function\n' + shopt -s extglob + ble/test '[[ ${value//$pattern/'"$qnl"'} == '"$qnl"'hello'"$qnl"' ]]' + shopt -u extglob + ble/test '[[ ${value//$pattern/'"$qnl"'} != '"$qnl"'hello'"$qnl"' ]]' +) +ble/test/end-section diff --git a/.local/src/blesh/lib/test-syntax.sh b/.local/src/blesh/lib/test-syntax.sh new file mode 100644 index 0000000..4e339a7 --- /dev/null +++ b/.local/src/blesh/lib/test-syntax.sh @@ -0,0 +1,39 @@ +# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license +ble-import lib/core-syntax +ble-import lib/core-test +ble/test/start-section 'ble/syntax' 22 +( + _func=ble/syntax:bash/simple-word/evaluate-last-brace-expansion + _collect='ret=$simple_ibrace/$ret' + ble/test "$_func 'a{b,c}x' ; $_collect" ret='6:2/acx' + ble/test "$_func 'a{b,{c,d}x' ; $_collect" ret='9:2/adx' + ble/test "$_func 'a{b,{c,d}}x'; $_collect" ret='10:2/adx' + ble/test "$_func 'a{{c,dx' ; $_collect" ret='5:1/adx' + ble/test "$_func 'a{b{c,dx' ; $_collect" ret='6:2/abdx' + ble/test "$_func 'a{b,c}{d}x' ; $_collect" ret='7:2/acd}x' +) +( + _func=ble/syntax:bash/simple-word/reconstruct-incomplete-word + _collect='ret=$?:$simple_flags:[$simple_ibrace]:$ret' + ble/test "$_func 'hello-word' ; $_collect" ret='0::[0:0]:hello-word' + ble/test "$_func 'hello word' ; $_collect" ret='1::[0:0]:hello' + ble/test "$_func 'hello-word\"a' ; $_collect" ret='0:D:[0:0]:hello-word"a"' + ble/test "$_func 'a{b,c}x' ; $_collect" ret='0::[6:2]:acx' + ble/test "$_func 'a{b,{c,d}x' ; $_collect" ret='0::[9:2]:adx' + ble/test "$_func 'a{b,{c,d}}x' ; $_collect" ret='0::[10:2]:adx' + ble/test "$_func 'a{{c,dx' ; $_collect" ret='0::[5:1]:adx' + ble/test "$_func 'a{b{c,dx' ; $_collect" ret='0::[6:2]:abdx' + ble/test "$_func 'a{b,c}{d}x' ; $_collect" ret='0::[7:2]:acd}x' + ble/test "$_func 'a{b,c}x\"hello, world'; $_collect" ret='0:D:[6:2]:acx"hello, world"' + ble/test "$_func 'a{b,{c,d}x'\''a' ; $_collect" ret='0:S:[9:2]:adx'\''a'\' + ble/test "$_func 'a{b,{c,d}}x\$'\''\e[m'; $_collect" ret='0:E:[10:2]:adx$'\''\e[m'\' + ble/test "$_func 'a{{c,dx\$\"aa' ; $_collect" ret='0:I:[5:1]:adx$"aa"' +) +( + _func=ble/syntax:bash/simple-word/evaluate-path-spec + _collect='ret="${spec[*]} >>> ${path[*]}"' + ble/test "$_func '~/a/b/c' ; $_collect" ret="~ ~/a ~/a/b ~/a/b/c >>> $HOME $HOME/a $HOME/a/b $HOME/a/b/c" + ble/test "$_func '~/a/b/c' / after-sep; $_collect" ret="~/ ~/a/ ~/a/b/ ~/a/b/c >>> $HOME/ $HOME/a/ $HOME/a/b/ $HOME/a/b/c" + ble/test "$_func '/x/y/z' / after-sep ; $_collect" ret="/ /x/ /x/y/ /x/y/z >>> / /x/ /x/y/ /x/y/z" +) +ble/test/end-section diff --git a/.local/src/blesh/lib/test-util.sh b/.local/src/blesh/lib/test-util.sh new file mode 100644 index 0000000..4ec1155 --- /dev/null +++ b/.local/src/blesh/lib/test-util.sh @@ -0,0 +1,1555 @@ +# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license +ble-import lib/core-test +ble/test/start-section 'ble/util' 1198 +( + ble/test 'bleopt a=1' \ + exit=2 + ble/test 'bleopt a' \ + stdout= exit=2 + ble/test 'bleopt a:=2' + ble/test 'bleopt a' \ + stdout="bleopt a=2" + ble/test '[[ $bleopt_a == 2 ]]' + ble/test "bleopt | grep 'bleopt a='" \ + stdout="bleopt a=2" + ble/test 'bleopt a=3' + ble/test 'bleopt a' \ + stdout="bleopt a=3" + function bleopt/check:a { value=123; } + ble/test 'bleopt a=4 && bleopt a' + stdout="bleopt a=123" + function bleopt/check:a { false; } + ble/test 'bleopt a=5' \ + exit=1 + ble/test 'bleopt a' \ + stdout="bleopt a=123" + ble/test bleopt f:=10 g:=11 + ble/test bleopt f g \ + stdout="bleopt f=10${_ble_term_nl}bleopt g=11" + ble/test bleopt f=12 g=13 + ble/test bleopt f g \ + stdout="bleopt f=12${_ble_term_nl}bleopt g=13" + ble/test bleopt/declare -v b 6 + ble/test bleopt b stdout="bleopt b=6" + ble/test bleopt/declare -n c 7 + ble/test bleopt c stdout="bleopt c=7" + ble/test bleopt d:= e:= + ble/test bleopt/declare -v d 8 + ble/test bleopt/declare -n e 9 + ble/test bleopt d stdout="bleopt d=" + ble/test bleopt e stdout="bleopt e=9" +) +ble/test ble/util/setexit 0 exit=0 +ble/test ble/util/setexit 1 exit=1 +ble/test ble/util/setexit 9 exit=9 +ble/test ble/util/setexit 128 exit=128 +ble/test ble/util/setexit 255 exit=255 +( + a=1 + function f1 { + echo g:$a + local a=2 + echo l:$a + ble/util/unlocal a + echo g:$a + a=3 + } + ble/test 'f1; echo g:$a' \ + stdout=g:1 \ + stdout=l:2 \ + stdout=g:1 \ + stdout=g:3 + function f2 { + echo f1:$a@f2 + local a=3 + echo f2:$a@f2 + ble/util/unlocal a + echo f1:$a@f2 + a=$a+ + } + function f1 { + echo g:$a@f1 + local a=2 + echo f1:$a@f1 + f2 + echo f1:$a@f1 + ble/util/unlocal a + echo g:$a@f1 + a=$a+ + } + ble/test 'a=1; f1; echo g:$a@g' \ + stdout=g:1@f1 \ + stdout=f1:2@f1 \ + stdout=f1:2@f2 \ + stdout=f2:3@f2 \ + stdout=f1:2@f2 \ + stdout=f1:2+@f1 \ + stdout=g:1@f1 \ + stdout=g:1+@g +) +( + function f1 { + local a=1 b=2 + local result=$((a+b)) + local "$1" && ble/util/upvar "$1" "$result" + } + ble/test 'f1 x; ret=$x' ret=3 + ble/test 'f1 a; ret=$a' ret=3 + ble/test 'f1 result; ret=$result' ret=3 + function f2 { + local a=1 + local -a b=(2) + local -a result=($((a+b[0])) y z) + local "$1" && ble/util/uparr "$1" "${result[@]}" + } + ble/test 'f2 x; ret="(${x[*]})"' ret='(3 y z)' + ble/test 'f2 a; ret="(${a[*]})"' ret='(3 y z)' + ble/test 'f2 b; ret="(${b[*]})"' ret='(3 y z)' + ble/test 'f2 result; ret="(${result[*]})"' ret='(3 y z)' +) +( + VARNAMES=(name x y count data) + function print-status { + echo "name=$name x=$x y=$y count=$count data=(${data[*]})" + } + function f1 { + local "${VARNAMES[@]/%/=}" # WA #D1570 checked + name=1 x=2 y=3 count=4 data=(aa bb cc dd) + print-status + ble/util/save-vars save1_ "${VARNAMES[@]}" + name=one x= y=A count=1 data=(Q) + print-status + ble/util/save-vars save2_ "${VARNAMES[@]}" + ble/util/restore-vars save1_ "${VARNAMES[@]}" + print-status + ble/util/restore-vars save2_ "${VARNAMES[@]}" + print-status + } + ble/test f1 \ + stdout='name=1 x=2 y=3 count=4 data=(aa bb cc dd)' \ + stdout='name=one x= y=A count=1 data=(Q)' \ + stdout='name=1 x=2 y=3 count=4 data=(aa bb cc dd)' \ + stdout='name=one x= y=A count=1 data=(Q)' +) +( + declare v=1 + declare -i i=1 + export x=2 + readonly r=3 + declare -a a=() + if ((_ble_bash>=40000)); then + declare -A A=() + declare -u u=a + declare -l l=B + declare -c c=c + fi + if ((_ble_bash>=40300)); then + declare -n n=r + fi + ble/test 'ble/variable#get-attr v; ret=$attr' ret= + ble/test 'ble/variable#get-attr i; ret=$attr' ret=i + ble/test 'ble/variable#get-attr x; ret=$attr' ret=x + ble/test 'ble/variable#get-attr r; ret=$attr' ret=r + ble/test 'ble/variable#get-attr a; ret=$attr' ret=a + if ((_ble_bash>=40000)); then + ble/test 'ble/variable#get-attr u; ret=$attr' ret=u + ble/test 'ble/variable#get-attr l; ret=$attr' ret=l + ble/test 'ble/variable#get-attr c; ret=$attr' ret=c + ble/test 'ble/variable#get-attr A; ret=$attr' ret=A + fi + ble/test 'ble/variable#has-attr i i' + ble/test 'ble/variable#has-attr x x' + ble/test 'ble/variable#has-attr r r' + ble/test 'ble/variable#has-attr a a' + ble/test 'ble/variable#has-attr v i' exit=1 + ble/test 'ble/variable#has-attr v x' exit=1 + ble/test 'ble/variable#has-attr v r' exit=1 + ble/test 'ble/variable#has-attr v a' exit=1 + if ((_ble_bash>=40000)); then + ble/test 'ble/variable#has-attr u u' + ble/test 'ble/variable#has-attr l l' + ble/test 'ble/variable#has-attr c c' + ble/test 'ble/variable#has-attr A A' + ble/test 'ble/variable#has-attr v u' exit=1 + ble/test 'ble/variable#has-attr v l' exit=1 + ble/test 'ble/variable#has-attr v c' exit=1 + ble/test 'ble/variable#has-attr v A' exit=1 + fi + ble/test 'ble/is-inttype i' + ble/test 'ble/is-inttype v' exit=1 + ble/test 'ble/is-readonly r' + ble/test 'ble/is-readonly v' exit=1 + if ((_ble_bash>=40000)); then + ble/test 'ble/is-transformed u' + ble/test 'ble/is-transformed l' + ble/test 'ble/is-transformed c' + ble/test 'ble/is-transformed v' exit=1 + fi +) +function is-global() (readonly "$1"; ! local "$1" 2>/dev/null) +( + v1=1 v2=2 + ((_ble_bash>=40200)) && + declare -g v1u v2u + function f1 { + local v2=22 v3=33 + local v2u v3u + f2 + } + function f2 { + local v4=444 v4u + ble/test 'is-global v0' + ble/test 'is-global v1' + ble/test 'is-global v2' exit=1 + ble/test 'is-global v3' exit=1 + ble/test 'is-global v4' exit=1 + ble/test 'ble/variable#is-global v0' + ble/test 'ble/variable#is-global v1' + ble/test 'ble/variable#is-global v2' exit=1 + ble/test 'ble/variable#is-global v3' exit=1 + ble/test 'ble/variable#is-global v4' exit=1 + ble/test 'ble/variable#is-global v0u' + if ((_ble_bash>=40200)); then + ble/test 'ble/variable#is-global v1u' + ble/test 'ble/variable#is-global v2u' exit=1 + fi + ble/test 'ble/variable#is-global v3u' exit=1 + ble/test 'ble/variable#is-global v4u' exit=1 + } + f1 +) +( + _ble_array_prototype=() + ble/test 'echo ${#_ble_array_prototype[@]}' stdout=0 + ble/array#reserve-prototype 10 + ble/test 'echo ${#_ble_array_prototype[@]}' stdout=10 + ble/test 'x=("${_ble_array_prototype[@]::10}"); echo ${#x[@]}' stdout=10 + ble/array#reserve-prototype 3 + ble/test 'echo ${#_ble_array_prototype[@]}' stdout=10 + ble/test 'x=("${_ble_array_prototype[@]::3}"); echo ${#x[@]}' stdout=3 +) +( + declare -a a=() + declare b= + ble/test 'ble/is-array a' + ble/test 'ble/is-array b' exit=1 + ble/test 'ble/is-array c' exit=1 + if ((_ble_bash>=40000)); then + declare -A A=() + ble/test 'ble/is-array A' exit=1 + ble/test 'ble/is-assoc a' exit=1 + ble/test 'ble/is-assoc A' + ble/test 'ble/is-assoc b' exit=1 + ble/test 'ble/is-assoc c' exit=1 + fi +) +( + ble/test 'ble/array#set a; echo "${#a[@]}:(${a[*]})"' stdout='0:()' + ble/test 'ble/array#set a Q; echo "${#a[@]}:(${a[*]})"' stdout='1:(Q)' + ble/test 'ble/array#set a 1 2 3; echo "${#a[@]}:(${a[*]})"' stdout='3:(1 2 3)' + ble/test 'ble/array#set a; echo "${#a[@]}:(${a[*]})"' stdout='0:()' +) +( + declare -a a=() + ble/array#push a + ble/test 'echo "${#a[@]}:(${a[*]})"' stdout='0:()' + ble/array#push a A + ble/test 'echo "${#a[@]}:(${a[*]})"' stdout='1:(A)' + ble/array#push a B C + ble/test 'echo "${#a[@]}:(${a[*]})"' stdout='3:(A B C)' + ble/array#push a + ble/test 'echo "${#a[@]}:(${a[*]})"' stdout='3:(A B C)' +) +( + function result { echo "$ret:${#arr[*]}:(${arr[*]})"; } + ble/test 'arr=() ; ble/array#pop arr; result' stdout=':0:()' + ble/test 'arr=(1) ; ble/array#pop arr; result' stdout='1:0:()' + ble/test 'arr=(1 2) ; ble/array#pop arr; result' stdout='2:1:(1)' + ble/test 'arr=(0 0 0); ble/array#pop arr; result' stdout='0:2:(0 0)' + ble/test 'arr=(1 2 3); ble/array#pop arr; result' stdout='3:2:(1 2)' + ble/test 'arr=(" a a " " b b " " c c "); ble/array#pop arr; result' \ + stdout=' c c :2:( a a b b )' +) +( + function status { echo "${#a[@]}:(${a[*]})"; } + a=() + ble/array#unshift a + ble/test status stdout='0:()' + ble/array#unshift a A + ble/test status stdout='1:(A)' + ble/array#unshift a + ble/test status stdout='1:(A)' + ble/array#unshift a B + ble/test status stdout='2:(B A)' + ble/array#unshift a C D E + ble/test status stdout='5:(C D E B A)' + a=() + ble/array#unshift a A B + ble/test status stdout='2:(A B)' +) +( + function status { echo "${#a[@]}:(${a[*]})"; } + a=(); ble/array#reverse a + ble/test status stdout='0:()' + a=(1); ble/array#reverse a + ble/test status stdout='1:(1)' + a=(xy zw); ble/array#reverse a + ble/test status stdout='2:(zw xy)' + a=(a 3 x); ble/array#reverse a + ble/test status stdout='3:(x 3 a)' + a=({1..10}) b=({10..1}); ble/array#reverse a + ble/test status stdout="10:(${b[*]})" + a=({1..9}) b=({9..1}); ble/array#reverse a + ble/test status stdout="9:(${b[*]})" +) +( + function status { echo "${#a[@]}:(${a[*]})"; } + a=(); ble/array#insert-at a 0 A B C + ble/test status stdout='3:(A B C)' + a=(); ble/array#insert-at a 1 A B C + ble/test status stdout='3:(A B C)' + a=(x y z); ble/array#insert-at a 0 A + ble/test status stdout='4:(A x y z)' + a=(x y z); ble/array#insert-at a 1 A + ble/test status stdout='4:(x A y z)' + a=(x y z); ble/array#insert-at a 3 A + ble/test status stdout='4:(x y z A)' + a=(x y z); ble/array#insert-at a 0 A B C + ble/test status stdout='6:(A B C x y z)' + a=(x y z); ble/array#insert-at a 1 A B C + ble/test status stdout='6:(x A B C y z)' + a=(x y z); ble/array#insert-at a 3 A B C + ble/test status stdout='6:(x y z A B C)' + a=(x y z); ble/array#insert-at a 0 + ble/test status stdout='3:(x y z)' + a=(x y z); ble/array#insert-at a 1 + ble/test status stdout='3:(x y z)' + a=(x y z); ble/array#insert-at a 3 + ble/test status stdout='3:(x y z)' +) +( + function status { echo "${#a[@]}:(${a[*]})"; } + a=(hello world hello world) + ble/array#insert-after a hello 1 2 3 + ble/test status stdout='7:(hello 1 2 3 world hello world)' + a=(heart world hello world) + ble/array#insert-after a hello 1 2 3 + ble/test status stdout='7:(heart world hello 1 2 3 world)' + a=(hello world hello world) + ble/test 'ble/array#insert-after a check 1 2 3' exit=1 + ble/test status stdout='4:(hello world hello world)' +) +( + function status { echo "${#a[@]}:(${a[*]})"; } + a=(hello world this) + ble/array#insert-before a this with check + ble/test status stdout='5:(hello world with check this)' + a=(hello world this) + ble/test 'ble/array#insert-before a haystack kick check' exit=1 + ble/test status stdout='3:(hello world this)' +) +( + function status { echo "${#a[@]}:(${a[*]})"; } + a=(xxx yyy xxx yyy yyy xxx fdsa fdsa) + ble/array#remove a xxx + ble/test status stdout='5:(yyy yyy yyy fdsa fdsa)' + a=(aa aa aa aa aa) + ble/array#remove a bb + ble/test status stdout='5:(aa aa aa aa aa)' + ble/array#remove a aa + ble/test status stdout='0:()' + ble/array#remove a cc + ble/test status stdout='0:()' +) +( + a=(hello world this hello world) + ble/test 'ble/array#index a hello' ret=0 + a=(world hep this hello world) + ble/test 'ble/array#index a hello' ret=3 + a=(hello world this hello world) + ble/test 'ble/array#index a check' ret=-1 +) +( + a=(hello world this hello world) + ble/test 'ble/array#last-index a hello' ret=3 + a=(world hep this hello world) + ble/test 'ble/array#last-index a hello' ret=3 + a=(hello world this hello world) + ble/test 'ble/array#last-index a check' ret=-1 +) +( + function status { echo "${#a[@]}:(${a[*]})"; } + a=() + ble/test 'ble/array#remove-at a 0; status' stdout='0:()' + ble/test 'ble/array#remove-at a 10; status' stdout='0:()' + a=(x y z) + ble/test 'ble/array#remove-at a 4; status' stdout='3:(x y z)' + ble/test 'ble/array#remove-at a 3; status' stdout='3:(x y z)' + ble/test 'ble/array#remove-at a 1; status' stdout='2:(x z)' + ble/test 'ble/array#remove-at a 0; status' stdout='1:(z)' + ble/test 'ble/array#remove-at a 0; status' stdout='0:()' + a=({a..z}) a1=({a..y}) a2=({b..y}) a3=({b..h} {j..y}) + ble/test 'ble/array#remove-at a 25; status' stdout="25:(${a1[*]})" + ble/test 'ble/array#remove-at a 0; status' stdout="24:(${a2[*]})" + ble/test 'ble/array#remove-at a 7; status' stdout="23:(${a3[*]})" +) +( + _ble_string_prototype=' ' + ble/test 'echo ${#_ble_string_prototype}' stdout=8 + ble/string#reserve-prototype 10 + ble/test 'echo ${#_ble_string_prototype}' stdout=16 + ble/test 'x=${_ble_string_prototype::10}; echo ${#x}' stdout=10 + ble/string#reserve-prototype 3 + ble/test 'echo ${#_ble_string_prototype}' stdout=16 + ble/test 'x=${_ble_string_prototype::3}; echo ${#x}' stdout=3 + ble/string#reserve-prototype 77 + ble/test 'echo ${#_ble_string_prototype}' stdout=128 + ble/test 'x=${_ble_string_prototype::77}; echo ${#x}' stdout=77 +) +( + ble/test 'ble/string#repeat' ret= + ble/test 'ble/string#repeat ""' ret= + ble/test 'ble/string#repeat a' ret= + ble/test 'ble/string#repeat abc' ret= + ble/test 'ble/string#repeat "" ""' ret= + ble/test 'ble/string#repeat a ""' ret= + ble/test 'ble/string#repeat abc ""' ret= + ble/test 'ble/string#repeat "" 0' ret= + ble/test 'ble/string#repeat a 0' ret= + ble/test 'ble/string#repeat abc 0' ret= + ble/test 'ble/string#repeat "" 1' ret= + ble/test 'ble/string#repeat "" 10' ret= + ble/test 'ble/string#repeat a 1' ret=a + ble/test 'ble/string#repeat a 2' ret=aa + ble/test 'ble/string#repeat a 5' ret=aaaaa + ble/test 'ble/string#repeat abc 1' ret=abc + ble/test 'ble/string#repeat abc 2' ret=abcabc + ble/test 'ble/string#repeat abc 5' ret=abcabcabcabcabc + ble/test 'ble/string#repeat ";&|<>" 5' ret=';&|<>;&|<>;&|<>;&|<>;&|<>' +) +( + ble/test 'ble/string#common-prefix' ret= + ble/test 'ble/string#common-prefix ""' ret= + ble/test 'ble/string#common-prefix a' ret= + ble/test 'ble/string#common-prefix "" ""' ret= + ble/test 'ble/string#common-prefix a ""' ret= + ble/test 'ble/string#common-prefix a b' ret= + ble/test 'ble/string#common-prefix a a' ret=a + ble/test 'ble/string#common-prefix abc abc' ret=abc + ble/test 'ble/string#common-prefix abc aaa' ret=a + ble/test 'ble/string#common-prefix abc ccc' ret= + ble/test 'ble/string#common-prefix abc xyz' ret= +) +( + ble/test 'ble/string#common-suffix' ret= + ble/test 'ble/string#common-suffix ""' ret= + ble/test 'ble/string#common-suffix a' ret= + ble/test 'ble/string#common-suffix "" ""' ret= + ble/test 'ble/string#common-suffix a ""' ret= + ble/test 'ble/string#common-suffix a b' ret= + ble/test 'ble/string#common-suffix a a' ret=a + ble/test 'ble/string#common-suffix abc abc' ret=abc + ble/test 'ble/string#common-suffix abc aaa' ret= + ble/test 'ble/string#common-suffix abc ccc' ret=c + ble/test 'ble/string#common-suffix abc xyz' ret= +) +( + function status { echo "${#a[@]}:(""${a[*]}"")"; } + nl=$'\n' + ble/test 'ble/string#split a , "" ; status' stdout='1:()' + ble/test 'ble/string#split a , "1" ; status' stdout='1:(1)' + ble/test 'ble/string#split a , "," ; status' stdout='2:( )' + ble/test 'ble/string#split a , "1," ; status' stdout='2:(1 )' + ble/test 'ble/string#split a , ",2" ; status' stdout='2:( 2)' + ble/test 'ble/string#split a , "1,,3" ; status' stdout='3:(1 3)' + ble/test 'ble/string#split a , "1,2,3" ; status' stdout='3:(1 2 3)' + ble/test 'ble/string#split a " " "1 2 3"; status' stdout='3:(1 2 3)' + ble/test 'ble/string#split a " " "1 2 3"; status' stdout='1:(1 2 3)' + ble/test 'ble/string#split a " " "1'"$nl"'2'"$nl"'3"; status' stdout="1:(1${nl}2${nl}3)" +) +( + function status { echo "${#a[@]}:(${a[*]})"; } + nl=$'\n' ht=$'\t' + ble/test 'ble/string#split-words a "" ; status' stdout='0:()' + ble/test 'ble/string#split-words a "1" ; status' stdout='1:(1)' + ble/test 'ble/string#split-words a " " ; status' stdout='0:()' + ble/test 'ble/string#split-words a "1 " ; status' stdout='1:(1)' + ble/test 'ble/string#split-words a " 2" ; status' stdout='1:(2)' + ble/test 'ble/string#split-words a "1 3" ; status' stdout='2:(1 3)' + ble/test 'ble/string#split-words a "1 2 3"; status' stdout='3:(1 2 3)' + ble/test 'ble/string#split-words a " 1'"$ht"'2'"$ht"'3 "; status' stdout='3:(1 2 3)' + ble/test 'ble/string#split-words a " 1'"$nl"'2'"$nl"'3 "; status' stdout='3:(1 2 3)' +) +( + function status { echo "${#a[@]}:(""${a[*]}"")"; } + nl=$'\n' ht=$'\t' + ble/test 'ble/string#split-lines a "" ; status' stdout='1:()' + ble/test 'ble/string#split-lines a "1" ; status' stdout='1:(1)' + ble/test 'ble/string#split-lines a "'"$nl"'" ; status' stdout='2:( )' + ble/test 'ble/string#split-lines a "1'"$nl"'" ; status' stdout='2:(1 )' + ble/test 'ble/string#split-lines a "'"$nl"'2" ; status' stdout='2:( 2)' + ble/test 'ble/string#split-lines a "1'"$nl$nl"'3" ; status' stdout='3:(1 3)' + ble/test 'ble/string#split-lines a "1'"$nl"'2'"$nl"'3"; status' stdout='3:(1 2 3)' + ble/test 'ble/string#split-lines a "1'"$ht"'2'"$ht"'3"; status' stdout="1:(1${ht}2${ht}3)" + ble/test 'ble/string#split-lines a "1 2 3"; status' stdout="1:(1 2 3)" +) +( + ble/test 'ble/string#count-char hello a' ret=0 + ble/test 'ble/string#count-char hello あ' ret=0 + ble/test 'ble/string#count-char hello e' ret=1 + ble/test 'ble/string#count-char hello l' ret=2 + ble/test 'ble/string#count-char hello olh' ret=4 + ble/test 'ble/string#count-char hello hello' ret=5 + ble/test 'ble/string#count-char "" a' ret=0 + ble/test 'ble/string#count-char "" ab' ret=0 +) +( + ble/test 'ble/string#count-string hello a' ret=0 + ble/test 'ble/string#count-string hello あ' ret=0 + ble/test 'ble/string#count-string hello ee' ret=0 + ble/test 'ble/string#count-string hello e' ret=1 + ble/test 'ble/string#count-string hello l' ret=2 + ble/test 'ble/string#count-string hello ll' ret=1 + ble/test 'ble/string#count-string hello hello' ret=1 + ble/test 'ble/string#count-string "" a' ret=0 + ble/test 'ble/string#count-string "" ab' ret=0 + ble/test 'ble/string#count-string ababababa aba' ret=2 +) +( + ble/test 'ble/string#index-of hello a' ret=-1 + ble/test 'ble/string#index-of hello あ' ret=-1 + ble/test 'ble/string#index-of hello ee' ret=-1 + ble/test 'ble/string#index-of hello e' ret=1 + ble/test 'ble/string#index-of hello l' ret=2 + ble/test 'ble/string#index-of hello ll' ret=2 + ble/test 'ble/string#index-of hello hello' ret=0 + ble/test 'ble/string#index-of "" a' ret=-1 + ble/test 'ble/string#index-of "" ab' ret=-1 + ble/test 'ble/string#index-of ababababa aba' ret=0 +) +( + ble/test 'ble/string#last-index-of hello a' ret=-1 + ble/test 'ble/string#last-index-of hello あ' ret=-1 + ble/test 'ble/string#last-index-of hello ee' ret=-1 + ble/test 'ble/string#last-index-of hello e' ret=1 + ble/test 'ble/string#last-index-of hello l' ret=3 + ble/test 'ble/string#last-index-of hello ll' ret=2 + ble/test 'ble/string#last-index-of hello hello' ret=0 + ble/test 'ble/string#last-index-of "" a' ret=-1 + ble/test 'ble/string#last-index-of "" ab' ret=-1 + ble/test 'ble/string#last-index-of ababababa aba' ret=6 +) +( + ble/test 'ble/string#toggle-case' ret= + ble/test 'ble/string#tolower ' ret= + ble/test 'ble/string#toupper ' ret= + ble/test 'ble/string#capitalize ' ret= + ble/test 'ble/string#toggle-case ""' ret= + ble/test 'ble/string#tolower ""' ret= + ble/test 'ble/string#toupper ""' ret= + ble/test 'ble/string#capitalize ""' ret= + ble/test 'ble/string#toggle-case a' ret=A + ble/test 'ble/string#tolower a' ret=a + ble/test 'ble/string#toupper a' ret=A + ble/test 'ble/string#capitalize a' ret=A + ble/test 'ble/string#toggle-case あ' ret=あ + ble/test 'ble/string#tolower あ' ret=あ + ble/test 'ble/string#toupper あ' ret=あ + ble/test 'ble/string#capitalize あ' ret=あ + ble/test 'ble/string#toggle-case +' ret=+ + ble/test 'ble/string#tolower +' ret=+ + ble/test 'ble/string#toupper +' ret=+ + ble/test 'ble/string#capitalize +' ret=+ + ble/test 'ble/string#toggle-case abc' ret=ABC + ble/test 'ble/string#tolower abc' ret=abc + ble/test 'ble/string#toupper abc' ret=ABC + ble/test 'ble/string#capitalize abc' ret=Abc + ble/test 'ble/string#toggle-case ABC' ret=abc + ble/test 'ble/string#tolower ABC' ret=abc + ble/test 'ble/string#toupper ABC' ret=ABC + ble/test 'ble/string#capitalize ABC' ret=Abc + ble/test 'ble/string#toggle-case aBc' ret=AbC + ble/test 'ble/string#tolower aBc' ret=abc + ble/test 'ble/string#toupper aBc' ret=ABC + ble/test 'ble/string#capitalize aBc' ret=Abc + ble/test 'ble/string#toggle-case +aBc' ret=+AbC + ble/test 'ble/string#tolower +aBc' ret=+abc + ble/test 'ble/string#toupper +aBc' ret=+ABC + ble/test 'ble/string#capitalize +aBc' ret=+Abc + ble/test 'ble/string#capitalize "hello world"' ret='Hello World' + LC_ALL=en_US.utf8 + ble/test 'ble/string#toggle-case +aBc' ret=+AbC + ble/test 'ble/string#tolower +aBc' ret=+abc + ble/test 'ble/string#toupper +aBc' ret=+ABC + ble/test 'ble/string#capitalize +aBc' ret=+Abc + ble/test 'ble/string#capitalize "hello world"' ret='Hello World' +) +( + ble/test 'ble/string#trim ' ret= + ble/test 'ble/string#ltrim' ret= + ble/test 'ble/string#rtrim' ret= + ble/test 'ble/string#trim ""' ret= + ble/test 'ble/string#ltrim ""' ret= + ble/test 'ble/string#rtrim ""' ret= + ble/test 'ble/string#trim "a"' ret=a + ble/test 'ble/string#ltrim "a"' ret=a + ble/test 'ble/string#rtrim "a"' ret=a + ble/test 'ble/string#trim " a "' ret=a + ble/test 'ble/string#ltrim " a "' ret='a ' + ble/test 'ble/string#rtrim " a "' ret=' a' + ble/test 'ble/string#trim " a b "' ret='a b' + ble/test 'ble/string#ltrim " a b "' ret='a b ' + ble/test 'ble/string#rtrim " a b "' ret=' a b' + ble/test 'ble/string#trim "abc"' ret='abc' + ble/test 'ble/string#ltrim "abc"' ret='abc' + ble/test 'ble/string#rtrim "abc"' ret='abc' + ble/test 'ble/string#trim " abc "' ret='abc' + ble/test 'ble/string#ltrim " abc "' ret='abc ' + ble/test 'ble/string#rtrim " abc "' ret=' abc' + for pad in $' \t\n \t\n' $'\t\t\t' $'\n\n\n'; do + ble/test 'ble/string#trim "'"$pad"'abc'"$pad"'"' ret='abc' + ble/test 'ble/string#ltrim "'"$pad"'abc'"$pad"'"' ret="abc${pad}" + ble/test 'ble/string#rtrim "'"$pad"'abc'"$pad"'"' ret="${pad}abc" + done +) +( + ble/test 'ble/string#escape-characters hello' ret=hello + ble/test 'ble/string#escape-characters hello ""' ret=hello + ble/test 'ble/string#escape-characters hello xyz' ret=hello + ble/test 'ble/string#escape-characters hello el' ret='h\e\l\lo' + ble/test 'ble/string#escape-characters hello hl XY' ret='\Xe\Y\Yo' + ble/test 'ble/string#escape-for-sed-regex "A\.[*?+|^\$(){}/"' \ + ret='A\\\.\[\*?+|\^\$(){}\/' + ble/test 'ble/string#escape-for-awk-regex "A\.[*?+|^\$(){}/"' \ + ret='A\\\.\[\*\?\+\|\^\$\(\)\{\}\/' + ble/test 'ble/string#escape-for-extended-regex "A\.[*?+|^\$(){}/"' \ + ret='A\\\.\[\*\?\+\|\^\$\(\)\{\}/' + ble/test 'ble/string#escape-for-bash-glob "A\*?[("' ret='A\\\*\?\[\(' + ble/test 'ble/string#escape-for-bash-single-quote "A'\''B"' ret="A'\''B" + ble/test 'ble/string#escape-for-bash-double-quote "hello \$ \` \\ ! world"' ret='hello \$ \` \\ "\!" world' + input=A$'\\\a\b\e\f\n\r\t\v'\'B output=A'\\\a\b\e\f\n\r\t\v\'\'B + ble/test 'ble/string#escape-for-bash-escape-string "$input"' ret="$output" + ble/test 'ble/string#escape-for-bash-specialchars "[hello] (world) {this,is} <test>"' \ + ret='\[hello\]\ \(world\)\ {this,is}\ \<test\>' + ble/test 'ble/string#escape-for-bash-specialchars "[hello] (world) {this,is} <test>" b' \ + ret='\[hello\]\ \(world\)\ \{this\,is\}\ \<test\>' + ble/test 'ble/string#escape-for-bash-specialchars "a=b:c:d" c' \ + ret='a\=b\:c\:d' + ble/test $'ble/string#escape-for-bash-specialchars "a\tb\tc"' \ + ret=$'a\\\tb\\\tc' +) +( + ble/test 'ble/string#quote-command' ret= + ble/test 'ble/string#quote-command echo' ret='echo' + ble/test 'ble/string#quote-command echo hello world' ret="echo 'hello' 'world'" + ble/test 'ble/string#quote-command echo "hello world"' ret="echo 'hello world'" + ble/test 'ble/string#quote-command echo "'\''test'\''"' ret="echo ''\''test'\'''" + ble/test 'ble/string#quote-command echo "" "" ""' ret="echo '' '' ''" + ble/test 'ble/string#quote-command echo a{1..4}' ret="echo 'a1' 'a2' 'a3' 'a4'" + ble/test 'ble/util/print-quoted-command' stdout= + ble/test 'ble/util/print-quoted-command echo' stdout='echo' + ble/test 'ble/util/print-quoted-command echo hello world' stdout="echo 'hello' 'world'" + ble/test 'ble/util/print-quoted-command echo "hello world"' stdout="echo 'hello world'" + ble/test 'ble/util/print-quoted-command echo "'\''test'\''"' stdout="echo ''\''test'\'''" + ble/test 'ble/util/print-quoted-command echo "" "" ""' stdout="echo '' '' ''" + ble/test 'ble/util/print-quoted-command echo a{1..4}' stdout="echo 'a1' 'a2' 'a3' 'a4'" +) +( + ble/test 'ble/string#quote-word' ret= + ble/test 'ble/string#quote-word echo' ret='echo' + ble/test 'ble/string#quote-word "hello world"' ret="'hello world'" + ble/test 'ble/string#quote-word "'\''test'\''"' ret="\'test\'" + ble/test 'ble/string#quote-word "a'\''b'\''c"' ret="a\'b\'c" +) +( + ble/test 'ble/string#create-unicode-progress-bar 0 24 3' ret=' ' + ble/test 'ble/string#create-unicode-progress-bar 1 24 3' ret='▏ ' + ble/test 'ble/string#create-unicode-progress-bar 2 24 3' ret='▎ ' + ble/test 'ble/string#create-unicode-progress-bar 3 24 3' ret='▍ ' + ble/test 'ble/string#create-unicode-progress-bar 4 24 3' ret='▌ ' + ble/test 'ble/string#create-unicode-progress-bar 5 24 3' ret='▋ ' + ble/test 'ble/string#create-unicode-progress-bar 6 24 3' ret='▊ ' + ble/test 'ble/string#create-unicode-progress-bar 7 24 3' ret='▉ ' + ble/test 'ble/string#create-unicode-progress-bar 8 24 3' ret='█ ' + ble/test 'ble/string#create-unicode-progress-bar 9 24 3' ret='█▏ ' + ble/test 'ble/string#create-unicode-progress-bar 15 24 3' ret='█▉ ' + ble/test 'ble/string#create-unicode-progress-bar 16 24 3' ret='██ ' + ble/test 'ble/string#create-unicode-progress-bar 17 24 3' ret='██▏' + ble/test 'ble/string#create-unicode-progress-bar 24 24 3' ret='███' + ble/test 'ble/string#create-unicode-progress-bar 0 24 4 unlimited' ret=$'█ ' + ble/test 'ble/string#create-unicode-progress-bar 1 24 4 unlimited' ret=$'\e[7m▏\e[27m▏ ' + ble/test 'ble/string#create-unicode-progress-bar 2 24 4 unlimited' ret=$'\e[7m▎\e[27m▎ ' + ble/test 'ble/string#create-unicode-progress-bar 3 24 4 unlimited' ret=$'\e[7m▍\e[27m▍ ' + ble/test 'ble/string#create-unicode-progress-bar 4 24 4 unlimited' ret=$'\e[7m▌\e[27m▌ ' + ble/test 'ble/string#create-unicode-progress-bar 5 24 4 unlimited' ret=$'\e[7m▋\e[27m▋ ' + ble/test 'ble/string#create-unicode-progress-bar 6 24 4 unlimited' ret=$'\e[7m▊\e[27m▊ ' + ble/test 'ble/string#create-unicode-progress-bar 7 24 4 unlimited' ret=$'\e[7m▉\e[27m▉ ' + ble/test 'ble/string#create-unicode-progress-bar 8 24 4 unlimited' ret=$' █ ' + ble/test 'ble/string#create-unicode-progress-bar 9 24 4 unlimited' ret=$' \e[7m▏\e[27m▏ ' + ble/test 'ble/string#create-unicode-progress-bar 15 24 4 unlimited' ret=$' \e[7m▉\e[27m▉ ' + ble/test 'ble/string#create-unicode-progress-bar 16 24 4 unlimited' ret=$' █ ' + ble/test 'ble/string#create-unicode-progress-bar 17 24 4 unlimited' ret=$' \e[7m▏\e[27m▏' + ble/test 'ble/string#create-unicode-progress-bar 24 24 4 unlimited' ret=$'█ ' +) +( + ble/test 'ble/util/strlen' ret=0 + ble/test 'ble/util/strlen ""' ret=0 + ble/test 'ble/util/strlen a' ret=1 + ble/test 'ble/util/strlen abc' ret=3 + ble/test 'ble/util/strlen α' ret=2 + ble/test 'ble/util/strlen αβγ' ret=6 + ble/test 'ble/util/strlen あ' ret=3 + ble/test 'ble/util/strlen あいう' ret=9 + ble/test 'ble/util/strlen aα' ret=3 + ble/test 'ble/util/strlen aαあ' ret=6 + LC_ALL=en_US.utf8 + ble/test 'ble/util/strlen a' ret=1 + ble/test 'ble/util/strlen α' ret=2 + ble/test 'ble/util/strlen あ' ret=3 +) +( + ble/test 'ble/util/substr' ret= + ble/test 'ble/util/substr ""' ret= + ble/test 'ble/util/substr a' ret= + ble/test 'ble/util/substr "" 0' ret= + ble/test 'ble/util/substr "" 1' ret= + ble/test 'ble/util/substr a 0' ret= + ble/test 'ble/util/substr a 1' ret= + ble/test 'ble/util/substr a 2' ret= + ble/test 'ble/util/substr "" 0 0' ret= + ble/test 'ble/util/substr "" 0 1' ret= + ble/test 'ble/util/substr "" 1 1' ret= + ble/test 'ble/util/substr a 0 0' ret= + ble/test 'ble/util/substr a 1 0' ret= + ble/test 'ble/util/substr a 0 1' ret=a + ble/test 'ble/util/substr a 1 1' ret= + ble/test 'ble/util/substr abc 1 0' ret= + ble/test 'ble/util/substr abc 1 1' ret=b + ble/test 'ble/util/substr abc 1 2' ret=bc + ble/test 'ble/util/substr abc 0 0' ret= + ble/test 'ble/util/substr abc 0 1' ret=a + ble/test 'ble/util/substr abc 0 3' ret=abc + ble/test 'ble/util/substr abc 0 4' ret=abc + ble/test 'ble/util/substr abc 3 0' ret= + ble/test 'ble/util/substr abc 3 1' ret= + ble/test 'ble/util/substr abc 4 0' ret= + ble/test 'ble/util/substr abc 4 1' ret= + ble/test 'ble/util/substr あいう 0 3' ret=あ + ble/test 'ble/util/substr あいう 3 6' ret=いう + ble/test 'ble/util/substr あいう 0 1' ret=$'\xe3' + ble/test 'ble/util/substr あいう 1 2' ret=$'\x81\x82' + ble/test 'ble/util/substr あいう 1 4' ret=$'\x81\x82\xe3\x81' + ble/test 'ble/util/substr あいう 7 5' ret=$'\x81\x86' +) +( + for cmd in ble/path#{remove,remove-glob}; do + ble/test code:'ret=; '$cmd' ret' ret= + ble/test code:'ret=; '$cmd' ret ""' ret= + ble/test code:'ret=a; '$cmd' ret ""' ret=a + ble/test code:'ret=a; '$cmd' ret a' ret= + ble/test code:'ret=a; '$cmd' ret b' ret=a + ble/test code:'ret=a:a:a; '$cmd' ret a' ret= + ble/test code:'ret=aa; '$cmd' ret a' ret=aa + ble/test code:'ret=xyz:abc; '$cmd' ret ""' ret=xyz:abc + ble/test code:'ret=xyz:abc; '$cmd' ret xyz' ret=abc + ble/test code:'ret=xyz:abc; '$cmd' ret abc' ret=xyz + ble/test code:'ret=xyz:abc:tuv; '$cmd' ret xyz' ret=abc:tuv + ble/test code:'ret=xyz:abc:tuv; '$cmd' ret abc' ret=xyz:tuv + ble/test code:'ret=xyz:abc:tuv; '$cmd' ret tuv' ret=xyz:abc + ble/test code:'ret=xyz:xyz; '$cmd' ret xyz' ret= + ble/test code:'ret=xyz:abc:xyz; '$cmd' ret xyz' ret=abc + ble/test code:'ret=xyz:abc:xyz; '$cmd' ret abc' ret=xyz:xyz + ble/test code:'ret=xyz:xyz:xyz; '$cmd' ret xyz' ret= + done + ble/test code:'ret=a; ble/path#remove ret \?' ret=a + ble/test code:'ret=aa; ble/path#remove ret \?' ret=aa + ble/test code:'ret=a:b; ble/path#remove ret \?' ret=a:b + ble/test code:'ret=a:b:c; ble/path#remove ret \?' ret=a:b:c + ble/test code:'ret=aa:b:cc; ble/path#remove ret \?' ret=aa:b:cc + ble/test code:'ret=stdX:stdY:usrZ; ble/path#remove ret "std[a-zX-Z]"' ret=stdX:stdY:usrZ + ble/test code:'ret=stdX:usrZ:stdY; ble/path#remove ret "std[a-zX-Z]"' ret=stdX:usrZ:stdY + ble/test code:'ret=usrZ:stdX:stdY; ble/path#remove ret "std[a-zX-Z]"' ret=usrZ:stdX:stdY + ble/test code:'ret=a; ble/path#remove-glob ret \?' ret= + ble/test code:'ret=aa; ble/path#remove-glob ret \?' ret=aa + ble/test code:'ret=a:b; ble/path#remove-glob ret \?' ret= + ble/test code:'ret=a:b:c; ble/path#remove-glob ret \?' ret= + ble/test code:'ret=aa:b:cc; ble/path#remove-glob ret \?' ret=aa:cc + ble/test code:'ret=stdX:stdY:usrZ; ble/path#remove-glob ret "std[a-zX-Z]"' ret=usrZ + ble/test code:'ret=stdX:usrZ:stdY; ble/path#remove-glob ret "std[a-zX-Z]"' ret=usrZ + ble/test code:'ret=usrZ:stdX:stdY; ble/path#remove-glob ret "std[a-zX-Z]"' ret=usrZ +) +( + ble/test code:'ret=; ble/path#append ret a' ret=a + ble/test code:'ret=a; ble/path#append ret a' ret=a:a + ble/test code:'ret=a; ble/path#append ret b' ret=a:b + ble/test code:'ret=a:b; ble/path#append ret cd' ret=a:b:cd + ble/test code:'ret=; ble/path#prepend ret a' ret=a + ble/test code:'ret=a; ble/path#prepend ret a' ret=a:a + ble/test code:'ret=a; ble/path#prepend ret b' ret=b:a + ble/test code:'ret=a:b; ble/path#prepend ret cd' ret=cd:a:b + ble/test code:'ret=a:b:c; ble/path#contains ret a' + ble/test code:'ret=a:b:c; ble/path#contains ret b' + ble/test code:'ret=a:b:c; ble/path#contains ret c' + ble/test code:'ret=a:b:c; ! ble/path#contains ret x' + ble/test code:'ret=a:b:c; ! ble/path#contains ret aa' + ble/test code:'ret=a:b:c; ! ble/path#contains ret bb' + ble/test code:'ret=a:b:c; ! ble/path#contains ret cc' + ble/test code:'ret=a:b:c; ! ble/path#contains ret "?"' + ble/test code:'ret=a:b:c; ! ble/path#contains ret "*"' + ble/test code:'ret=abc:def; ble/path#contains ret abc' + ble/test code:'ret=abc:def; ble/path#contains ret def' + ble/test code:'ret=abc:def; ! ble/path#contains ret a' + ble/test code:'ret=abc:def; ! ble/path#contains ret ab' + ble/test code:'ret=abc:def; ! ble/path#contains ret abcdef' + ble/test code:'ret=abc:def; ! ble/path#contains ret "???"' + ble/test code:'ret=xyz; ble/path#contains ret xyz' + ble/test code:'ret=xyz; ! ble/path#contains ret xyz:xyz' + ble/test code:'ret=xyz; ! ble/path#contains ret "???"' +) +( + builtin eval -- "${_ble_util_dict_declare//NAME/dict1}" + builtin eval -- "${_ble_util_gdict_declare//NAME/dict2}" + builtin eval -- "${_ble_util_adict_declare//NAME/dict3}" + index=1 + for Dict in ble/{,g,a}dict; do + dict=dict$((index++)) + ret=unchanged + ble/test '! '$Dict'#has '$dict' banana' ret=unchanged + ble/test '! '$Dict'#has '$dict' ""' ret=unchanged + $Dict#set $dict apple red + $Dict#set $dict banana yellow + $Dict#set $dict orange orange + $Dict#set $dict melon green + ret=unchanged + ble/test $Dict'#has '$dict' banana' ret=unchanged # 先頭 + ble/test $Dict'#has '$dict' apple' ret=unchanged # 中 + ble/test $Dict'#has '$dict' melon' ret=unchanged # 末尾 + ble/test '! '$Dict'#has '$dict' pear' ret=unchanged # 存在しない項目 + ble/test $Dict'#get '$dict' banana' ret=yellow # 先頭 + ble/test $Dict'#get '$dict' apple' ret=red # 中 + ble/test $Dict'#get '$dict' melon' ret=green # 末尾 + ble/test '! '$Dict'#get '$dict' pear' ret= # 存在しない項目 + ble/test '! '$Dict'#has '$dict' ""' # 末尾空要素で引けるか + ble/test '! '$Dict'#get '$dict' ""' # 末尾空要素で引けるか + $Dict#set $dict '' transparent + ble/test $Dict'#has '$dict' ""' # 末尾空要素で引けるか + ble/test $Dict'#get '$dict' ""' ret=transparent # 末尾空要素で引けるか + $Dict#set $dict 'alpha beta' pink + ble/test $Dict'#has '$dict' ""' # 中央空要素で引けるか + ble/test $Dict'#has '$dict' "alpha beta"' # 空白を含む見出し + ble/test $Dict'#get '$dict' ""' ret=transparent # 中央空要素で引けるか + ble/test $Dict'#get '$dict' "alpha beta"' ret=pink # 空白を含む見出し + $Dict#set $dict ' apple ' ' red ' + ble/test $Dict'#has '$dict' " apple "' # 空白で trim されないか + ble/test $Dict'#has '$dict' apple' # 既存項目を破壊していないか + ble/test $Dict'#get '$dict' " apple "' ret=' red ' # 空白で trim されないか + ble/test $Dict'#get '$dict' apple' ret=red # 既存項目を破壊していないか + ble/test '! '$Dict'#has '$dict' "${_ble_term_FS}"' # 単一FS + ble/test '! '$Dict'#has '$dict' ":"' # 単一コロン + ble/test '! '$Dict'#has '$dict' "apple${_ble_term_FS}banana"' # FSを含む見出し + ble/test '! '$Dict'#has '$dict' apple:banana' # コロンを含む見出し + ble/test '! '$Dict'#get '$dict' "${_ble_term_FS}"' ret= # 単一FS + ble/test '! '$Dict'#get '$dict' ":"' ret= # 単一コロン + ble/test '! '$Dict'#get '$dict' "apple${_ble_term_FS}banana"' ret= # FSを含む見出し + ble/test '! '$Dict'#get '$dict' apple:banana' ret= # コロンを含む見出し + $Dict#set $dict "${_ble_term_FS}" Empty + $Dict#set $dict ":" Colon + $Dict#set $dict "apple${_ble_term_FS}banana" RedYellow + $Dict#set $dict "apple:banana" __red_yellow__ + ble/test $Dict'#has '$dict' "${_ble_term_FS}"' # 単一FS + ble/test $Dict'#has '$dict' ":"' # 単一コロン + ble/test $Dict'#has '$dict' "apple${_ble_term_FS}banana"' # FSを含む見出し + ble/test $Dict'#has '$dict' apple:banana' # コロンを含む見出し + ble/test $Dict'#get '$dict' "${_ble_term_FS}"' ret=Empty # 単一FS + ble/test $Dict'#get '$dict' ":"' ret=Colon # 単一コロン + ble/test $Dict'#get '$dict' "apple${_ble_term_FS}banana"' ret=RedYellow # FSを含む見出し + ble/test $Dict'#get '$dict' apple:banana' ret=__red_yellow__ # コロンを含む見出し + $Dict#unset $dict banana + $Dict#unset $dict apple + $Dict#unset $dict melon + ble/test '! '$Dict'#has '$dict' banana' + ble/test '! '$Dict'#has '$dict' apple' + ble/test '! '$Dict'#has '$dict' melon' + $Dict#unset $dict "" + $Dict#unset $dict "alpha beta" + $Dict#unset $dict " apple " + ble/test '! '$Dict'#has '$dict' ""' # 中央空要素で引けるか + ble/test '! '$Dict'#has '$dict' "alpha beta"' # 空白を含む見出し + ble/test '! '$Dict'#has '$dict' " apple "' # 空白で trim されないか + $Dict#unset $dict "${_ble_term_FS}" + $Dict#unset $dict ":" + $Dict#unset $dict "apple${_ble_term_FS}banana" + $Dict#unset $dict apple:banana + ble/test '! '$Dict'#has '$dict' "${_ble_term_FS}"' # 単一FS + ble/test '! '$Dict'#has '$dict' ":"' # 単一コロン + ble/test '! '$Dict'#has '$dict' "apple${_ble_term_FS}banana"' # FSを含む見出し + ble/test '! '$Dict'#has '$dict' apple:banana' # コロンを含む見出し + done +) +( + blehook/declare FOO + ble/test 'blehook --color=never FOO' stdout='blehook FOO=' + ble/test 'blehook/has-hook FOO' exit=1 + blehook FOO+='echo hello' + ble/test 'blehook --color=never FOO' \ + stdout="blehook FOO+='echo hello'" + ble/test 'blehook/has-hook FOO' + blehook FOO+='echo world' + ble/test 'blehook --color=never FOO' \ + stdout="blehook FOO+='echo hello'" \ + stdout="blehook FOO+='echo world'" + ble/test 'blehook/has-hook FOO' + blehook FOO-='echo hello' + ble/test 'blehook --color=never FOO' \ + stdout="blehook FOO+='echo world'" + ble/test 'blehook/has-hook FOO' + blehook FOO-='echo world' + ble/test 'blehook --color=never FOO' \ + stdout='blehook FOO=' + ble/test 'blehook/has-hook FOO' exit=1 + blehook FOO+='echo hello' + blehook FOO+='echo world' + blehook FOO='echo empty' + ble/test 'blehook --color=never FOO' \ + stdout="blehook FOO+='echo empty'" + ble/test 'blehook/has-hook FOO' + blehook FOO+='echo hello' + blehook FOO+='echo world' + blehook FOO= + ble/test 'blehook --color=never FOO' \ + stdout='blehook FOO=' + ble/test 'blehook/has-hook FOO' exit=1 + blehook FOO+='echo hello' + blehook FOO+='echo world' + blehook FOO!='echo hello' + ble/test 'blehook --color=never FOO' \ + stdout="blehook FOO+='echo hello'${_ble_term_nl}blehook FOO+='echo world'" + blehook FOO-+='echo hello' + ble/test 'blehook --color=never FOO' \ + stdout="blehook FOO+='echo world'${_ble_term_nl}blehook FOO+='echo hello'" + blehook FOO+-='echo hello' + ble/test 'blehook --color=never FOO' \ + stdout="blehook FOO+='echo hello'${_ble_term_nl}blehook FOO+='echo world'" + blehook FOO= + blehook FOO+='echo hello' + blehook FOO+='echo empty' + blehook FOO+='echo world' + ble/test 'blehook/invoke FOO' \ + stdout=hello \ + stdout=empty \ + stdout=world + blehook FOO='echo A$?' + blehook FOO+='echo B$?' + blehook FOO+='echo C$?' + ble/test 'ble/util/setexit 123; blehook/invoke FOO' \ + stdout=A123 \ + stdout=B123 \ + stdout=C123 + blehook/declare bar_load + blehook bar_load='echo bar_load' + ble/test 'blehook/eval-after-load bar "echo yes"' stdout= + ble/test 'blehook/invoke bar_load' \ + stdout=bar_load \ + stdout=yes + ble/test 'blehook/eval-after-load bar "echo next"' stdout=next + function func { ret="[$1]"; } + blehook FOO=func + ble/test 'blehook/invoke FOO xQAHbcpMFyFyQ' ret='[xQAHbcpMFyFyQ]' +) +( + ble/builtin/trap 'echo TRAPEXIT1' 0 + ble/test 'ble/builtin/trap/invoke 0' stdout=TRAPEXIT1 + ble/test 'ble/builtin/trap/invoke EXIT' stdout=TRAPEXIT1 + ble/builtin/trap 0 + ble/test 'ble/builtin/trap/invoke 0' stdout= + ble/builtin/trap 'echo TRAPEXIT2' EXIT + ble/test 'ble/builtin/trap/invoke 0' stdout=TRAPEXIT2 + ble/test 'ble/builtin/trap/invoke EXIT' stdout=TRAPEXIT2 + ble/builtin/trap EXIT + ble/test 'ble/builtin/trap/invoke 0' stdout= + ble/builtin/trap 'echo TRAPHUP1' 1 + ble/test 'ble/builtin/trap/invoke 1' stdout=TRAPHUP1 + ble/test 'ble/builtin/trap/invoke HUP' stdout=TRAPHUP1 + ble/test 'ble/builtin/trap/invoke SIGHUP' stdout=TRAPHUP1 + ble/builtin/trap 1 + ble/test 'ble/builtin/trap/invoke 1' stdout= + ble/builtin/trap 'echo TRAPHUP2' HUP + ble/test 'ble/builtin/trap/invoke 1' stdout=TRAPHUP2 + ble/test 'ble/builtin/trap/invoke HUP' stdout=TRAPHUP2 + ble/test 'ble/builtin/trap/invoke SIGHUP' stdout=TRAPHUP2 + ble/builtin/trap HUP + ble/test 'ble/builtin/trap/invoke HUP' stdout= + ble/builtin/trap 'echo TRAPHUP3' SIGHUP + ble/test 'ble/builtin/trap/invoke 1' stdout=TRAPHUP3 + ble/test 'ble/builtin/trap/invoke HUP' stdout=TRAPHUP3 + ble/test 'ble/builtin/trap/invoke SIGHUP' stdout=TRAPHUP3 + ble/builtin/trap SIGHUP + ble/test 'ble/builtin/trap/invoke HUP' stdout= + ble/builtin/trap/.register 9999 CUSTOM + ble/builtin/trap/reserve CUSTOM + ble/builtin/trap 'echo custom trap' CUSTOM + ble/test 'ble/builtin/trap/invoke CUSTOM' stdout='custom trap' + function ble/builtin/trap:CUSTOM { echo "__set_handler__ ($2) $1"; } + ble/test 'ble/builtin/trap "echo hello world" CUSTOM' \ + stdout='__set_handler__ (CUSTOM) echo hello world' + ble/test 'ble/builtin/trap/invoke CUSTOM' stdout='hello world' +) +( + ble/test 'ble/util/readfile ret <(echo hello)' \ + ret=hello$'\n' + ble/test 'ble/util/readfile ret <(echo hello; echo world)' \ + ret=hello$'\n'world$'\n' + ble/test 'ble/util/readfile ret <(echo hello; echo -n world)' \ + ret=hello$'\n'world + ble/test 'ble/util/readfile ret <(:)' ret= + function status { echo "${#a[*]}:(""${a[*]}"")"; } + ble/test "ble/util/mapfile a < <(echo hello); status" stdout='1:(hello)' + ble/test "ble/util/mapfile a < <(echo -n hello); status" stdout='1:(hello)' + ble/test "ble/util/mapfile a < <(echo hello; echo world); status" stdout='2:(hello world)' + ble/test "ble/util/mapfile a < <(echo hello; echo -n world); status" stdout='2:(hello world)' + ble/test "ble/util/mapfile a < <(printf '%s\n' h1 h2 h3 h4); status" stdout='4:(h1 h2 h3 h4)' + ble/test "ble/util/mapfile a < <(:); status" stdout='0:()' + ble/test "ble/util/mapfile a < <(echo); status" stdout='1:()' + ble/test "ble/util/mapfile a < <(echo;echo); status" stdout='2:( )' + ble/test "ble/util/mapfile a < <(echo a;echo;echo b); status" stdout='3:(a b)' + nl=$'\n' + ble/test 'ble/util/assign ret ""' ret= + ble/test 'ble/util/assign ret ":"' ret= + ble/test 'ble/util/assign ret "echo"' ret= + ble/test 'ble/util/assign ret "echo hello"' ret=hello + ble/test 'ble/util/assign ret "seq 5"' ret="1${nl}2${nl}3${nl}4${nl}5" + function f1 { echo stdout; echo stderr >&2; } + function nested-assign { + ble/util/assign err 'ble/util/assign out f1 2>&1' + echo "out=$out err=$err" + } + ble/test nested-assign stdout='out=stdout err=stderr' + ble/test 'ble/util/assign-array a :; status' stdout='0:()' + ble/test 'ble/util/assign-array a echo; status' stdout='1:()' + ble/test 'ble/util/assign-array a "echo hello"; status' stdout='1:(hello)' + ble/test 'ble/util/assign-array a "seq 5"; status' stdout='5:(1 2 3 4 5)' + ble/test 'ble/util/assign-array a "echo; echo; echo"; status' stdout='3:( )' + ble/test 'ble/util/assign-array a "echo 1; echo; echo 2"; status' stdout='3:(1 2)' +) +( + x=($'\177' $'\1' $'\2' $'\32' ' ' $'\a' $'\b' $'\t' $'\n' $'\v' $'\f' $'\r' a \" \' \$ \! \` \~) + x[0]=$'\177' + x[1]=$'\1' + ble/test "ble/util/writearray -d '' x | sha256sum | awk '{print \$1}'" stdout=$(printf '%s\0' "${x[@]}" | sha256sum | awk '{print $1}') +) +( + var=variable + alias ali=fun + function fun { echo yes "$*"; } + function ble/fun { echo yes "$*"; return 99; } + function ble/fun:type { echo yes "$*"; return 100; } + function ble/fun#meth { echo yes "$*"; return 101; } + ble/test 'ble/is-function' exit=1 + ble/test 'ble/is-function ""' exit=1 + ble/test 'ble/is-function fun' + ble/test 'ble/is-function ble/fun' + ble/test 'ble/is-function ble/fun:type' + ble/test 'ble/is-function ble/fun#meth' + ble/test 'ble/is-function fun1' exit=1 + ble/test 'ble/is-function ble/fun1' exit=1 + ble/test 'ble/is-function ble/fun1:type' exit=1 + ble/test 'ble/is-function ble/fun1#meth' exit=1 + ble/test 'ble/is-function ali' exit=1 + ble/test 'ble/is-function var' exit=1 + ble/test 'ble/is-function compgen' exit=1 + ble/test 'ble/is-function declare' exit=1 + ble/test 'ble/is-function mkfifo' exit=1 + function compgen { :; } + function declare { :; } + function mkfifo { :; } + ble/test 'ble/is-function compgen' + ble/test 'ble/is-function declare' + ble/test 'ble/is-function mkfifo' + ble/test 'ble/function#try fun 1 2 3' stdout='yes 1 2 3' + ble/test 'ble/function#try ble/fun 1 2 3' stdout='yes 1 2 3' exit=99 + ble/test 'ble/function#try ble/fun:type 1 2 3' stdout='yes 1 2 3' exit=100 + ble/test 'ble/function#try ble/fun#meth 1 2 3' stdout='yes 1 2 3' exit=101 + ble/test 'ble/function#try fun1 1 2 3' stdout= exit=127 + ble/test 'ble/function#try ble/fun1 1 2 3' stdout= exit=127 + ble/test 'ble/function#try ble/fun1:type 1 2 3' stdout= exit=127 + ble/test 'ble/function#try ble/fun1#meth 1 2 3' stdout= exit=127 +) +( + function f1 { echo original $*; } + ble/test f1 stdout='original' + ble/function#advice before f1 'echo pre' + ble/test f1 stdout={pre,original} + ble/function#advice after f1 'echo post' + ble/test f1 stdout={pre,original,post} + ble/function#advice before f1 'echo A' + ble/test f1 stdout={A,original,post} + ble/function#advice after f1 'echo B' + ble/test f1 stdout={A,original,B} + ble/function#advice around f1 'echo [; ble/function#advice/do; echo ]' + ble/test f1 stdout={A,[,original,],B} + ble/function#advice around f1 ' + ADVICE_WORDS[1]=quick + echo [; ble/function#advice/do; echo ] + ADVICE_EXIT=99' + ble/test f1 stdout={A,[,'original quick',],B} exit=99 + ble/function#advice remove f1 + ble/test f1 stdout='original' exit=0 + ble/test 'f1 1' stdout='original 1' exit=0 +) +( + ble/test 'echo 1 2 3' stdout='1 2 3' + ble/test 'ble/is-function echo' exit=1 + ble/function#push echo 'builtin echo "[$*]"' + ble/test 'ble/is-function echo' + ble/test 'echo 1 2 3' stdout='[1 2 3]' + ble/function#push echo 'builtin echo "($*)"' + ble/test 'echo 1 2 3' stdout='(1 2 3)' + ble/function#push echo 'builtin echo A; ble/function#push/call-top "$@"; builtin echo Z' + ble/test 'echo 1 2 3' stdout={A,'(1 2 3)',Z} + ble/function#push echo 'builtin echo [; ble/function#push/call-top "$@"; builtin echo ]' + ble/test 'echo 1 2 3' stdout={[,A,'(1 2 3)',Z,]} + ble/test 'ble/function#pop echo' + ble/test 'echo 1 2 3' stdout={A,'(1 2 3)',Z} + ble/function#pop echo + ble/test 'echo 1 2 3' stdout='(1 2 3)' + ble/function#pop echo + ble/test 'echo 1 2 3' stdout='[1 2 3]' + ble/test 'ble/is-function echo' + ble/test 'ble/function#pop echo' + ble/test 'ble/is-function echo' exit=1 + ble/test 'echo 1 2 3' stdout='1 2 3' + ble/test 'ble/function#pop echo' exit=1 + ble/test 'echo 1 2 3' stdout='1 2 3' +) +( + ble/test 'ble/util/set ret hello' ret='hello' + ble/test 'ble/util/set ret "hello world"' ret='hello world' + ble/test 'ble/util/set ret ""' ret='' + ble/test 'ble/util/set ret " "' ret=' ' + ble/test 'ble/util/set ret " a"' ret=' a' + ble/test 'ble/util/set ret "a "' ret='a ' + ble/test 'ble/util/set ret $'\''\n'\''' ret=$'\n' + ble/test 'ble/util/set ret A$'\''\n'\''' ret=A$'\n' + ble/test 'ble/util/set ret A$'\''\n'\''B' ret=A$'\n'B +) +( + ble/test 'ble/util/sprintf ret "[%s]" 1 2 3' ret='[1][2][3]' + ble/test 'ble/util/sprintf ret "[%5s]" 1' ret='[ 1]' + ble/test 'ble/util/sprintf ret "[%.2s]" 12345' ret='[12]' + ble/test 'ble/util/sprintf ret "[%d,%d]" 1 3' ret='[1,3]' + ble/test 'ble/util/sprintf ret "[%x]" 27' ret='[1b]' + ble/test 'ble/util/sprintf ret "[%#.2g]" 27' ret='[27.]' + ble/test 'ble/util/sprintf ret "[%#.2f]" 27' ret='[27.00]' +) +( + shopt -s expand_aliases + alias aaa=fun + function fun { :; } + function ble/fun { :; } + function ble/fun:type { :; } + function ble/fun#meth { :; } + ble/test 'ble/util/type ret aaa' ret=alias + ble/test 'ble/util/type ret fun' ret=function + ble/test 'ble/util/type ret alias' ret=builtin + ble/test 'ble/util/type ret mkfifo' ret=file + ble/test 'ble/util/type ret for' ret=keyword + ble/test 'ble/util/type ret ble/fun' ret=function + ble/test 'ble/util/type ret ble/fun:type' ret=function + ble/test 'ble/util/type ret ble/fun#meth' ret=function + ble/test 'ble/util/type ret fun1' ret= + ble/test 'ble/util/type ret ble/fun1' ret= + ble/test 'ble/util/type ret ble/fun1:type' ret= + ble/test 'ble/util/type ret ble/fun1#meth' ret= +) +( + shopt -s expand_aliases + alias aaa1='aaa2 world' + ble/test 'ble/alias#expand aaa1' ret='aaa2 world' + alias aaa2='aaa3 hello' + ble/test 'ble/alias#expand aaa2' ret='aaa3 hello' + ble/test 'ble/alias#expand aaa1' ret='aaa2 world' + alias aaa3='aaa4' + ble/test 'ble/alias#expand aaa3' ret='aaa4' + ble/test 'ble/alias#expand aaa2' ret='aaa3 hello' + ble/test 'ble/alias#expand aaa1' ret='aaa2 world' + alias aaa4='echo' + ble/test 'ble/alias#expand aaa4' ret='echo' + ble/test 'ble/alias#expand aaa3' ret='aaa4' + ble/test 'ble/alias#expand aaa2' ret='aaa3 hello' + ble/test 'ble/alias#expand aaa1' ret='aaa2 world' +) +if ((_ble_bash>=40000)); then + ( + ble/test 'echo 1 | { sleep 0.01; ble/util/is-stdin-ready; }' + ble/test 'sleep 0.01 | ble/util/is-stdin-ready' exit=1 + ble/test 'ble/util/is-stdin-ready <<< a' + ble/test 'ble/util/is-stdin-ready <<< ""' + ble/test ': | { sleep 0.01; ble/util/is-stdin-ready; }' + ble/test 'ble/util/is-stdin-ready < /dev/null' + ) +fi +ble/test ble/util/is-running-in-subshell exit=1 +( ble/test ble/util/is-running-in-subshell ) +( + ble/test/chdir + function getpid { + sh -c 'echo -n $PPID' >| a.txt + ble/util/readfile ppid a.txt + } + dummy=modification_to_environment.1 + ble/util/getpid + ble/test '[[ $BASHPID != $$ ]]' + getpid + ble/test code:'ret=$BASHPID' ret="$ppid" + pid1=$BASHPID + ( + dummy=modification_to_environment.2 + ble/util/getpid + ble/test '[[ $BASHPID != $$ && $BASHPID != $pid1 ]]' + getpid + ble/test '[[ $BASHPID == $ppid ]]' + ) + ble/test/rmdir +) +( + ble/test 'ble/fd#is-open 1' + ble/test 'ble/fd#is-open 2' + exec 9>&- + ble/test 'ble/fd#is-open 9' exit=1 + exec 9>/dev/null + ble/test 'ble/fd#is-open 9' + exec 9>&- + ble/test 'ble/fd#is-open 9' exit=1 +) +( + ble/test/chdir + ble/fd#alloc fd '> a.txt' + echo hello >&$fd + echo world >&$fd + if ((_ble_bash/100!=301)); then + ble/test 'ble/fd#close fd; echo test >&$fd' exit=1 + ble/test 'cat a.txt' stdout={hello,world} + fi + ble/test/rmdir +) +( + xv1='' + xv2a='a' xv2b='ab' + xv3a=' ' xv3b='a b' + xv4a=$'\n' xv4b=$'a\nb' + xv5a=$'\r' xv5b=$'a\rb' + xv6a=$'\x01' xv6b=a$'\x01'b + xv7a=$'\x02' xv7b=a$'\x02'b + xv8a=$'\x7F' xv8b=a$'\x7F'b + eval -- "$( + for name in v1 v{2..8}{a,b}; do + eval "$name=\$x$name" + done + ble/util/declare-print-definitions vn v1 v{2..8}{a,b} 2>/dev/null)" + ble/test '[[ ! ${vn+set} ]]' + for name in v1 v{2..8}{a,b}; do + ble/test "declare -p $name x$name | cat -A >&2; [[ \$$name == \$x$name ]]" + done + function status { eval 'ret="${#'$1'[*]}:(""${'$1'[*]}"")"'; } + xa0=() sa0='0:()' + xa1=('') sa1='1:()' + for k in {2..8}; do + eval "xa$k=(); xa$k[0]=\"\$xv${k}a\"; xa$k[1]=\"\$xv${k}b\"" + eval "sa$k=\"2:(\$xv${k}a \$xv${k}b)\"" + done + eval -- "$( + for name in a0 a1 a{2..8}; do + eval "$name=(\"\${x$name[@]}\")" + done + ble/util/declare-print-definitions a0 a1 a{2..8} 2>/dev/null)" + for name in a0 a1 a{2..8}; do + stdout_var=s$name + ble/test "status $name" ret="${!stdout_var}" + done +) +( + function status { builtin eval 'echo "${#'$1'[*]}:(""${'$1'[*]}"")"'; } + v1=123 v2=(1 2 3) v3=bbb v4=ccc + function f2 { + local v3=x v4=y + builtin eval -- "$(ble/util/print-global-definitions v{0..4})" + ble/test '[[ ! ${v0+set} ]]' + ble/test 'status v1' stdout='1:(123)' + ble/test 'status v2' stdout='3:(1 2 3)' + ble/test 'status v3' stdout='1:(bbb)' + ble/test 'status v4' stdout='1:(ccc)' + } + function f1 { + local v0=1 v1=2 v2=3 v4=5 + f2 + ble/test 'status v1' stdout='1:(2)' + ble/test 'status v2' stdout='1:(3)' + } + f1 + value="hello 'world'" + ble/test 'ble/util/print-global-definitions value' stdout="declare value='hello '\''world'\'''" +) +( + ble/test 'ble/util/has-glob-pattern "a*"' + ble/test 'ble/util/has-glob-pattern "a*b"' + ble/test 'ble/util/has-glob-pattern "?"' + ble/test 'ble/util/has-glob-pattern "a?"' + ble/test 'ble/util/has-glob-pattern "a?b"' + ble/test 'ble/util/has-glob-pattern "a?b*c"' + ble/test 'ble/util/has-glob-pattern "a[a-c]d"' + ble/test 'ble/util/has-glob-pattern "a[!a-c]d"' + ble/test 'ble/util/has-glob-pattern "*.txt"' + ble/test 'ble/util/has-glob-pattern "*.*"' + ble/test 'ble/util/has-glob-pattern ""' exit=1 + ble/test 'ble/util/has-glob-pattern "a"' exit=1 + ble/test 'ble/util/has-glob-pattern "abc"' exit=1 + ble/test 'ble/util/has-glob-pattern "/"' exit=1 + ble/test 'ble/util/has-glob-pattern "a/c"' exit=1 + ble/test 'ble/util/has-glob-pattern "a:b"' exit=1 + ble/test 'ble/util/has-glob-pattern "a=b"' exit=1 + ble/test 'ble/util/has-glob-pattern "\[xyz\]"' exit=1 +) +ble/util/msleep/.calibrate-loop &>/dev/null +ble/util/msleep/.calibrate-loop &>/dev/null +ble/util/msleep/.calibrate-loop &>/dev/null +( + ble/test 'ble-measure -q "ble/util/msleep 100"; echo "$ret usec" >&2; ((msec=ret/1000,90<=msec&&msec<=110))' + ble/test 'ble-measure -q "ble/util/sleep 0.1"; echo "$ret usec" >&2; ((msec=ret/1000,90<=msec&&msec<=110))' +) +( + time=0 + ble/function#push ble/util/msleep '((time+=$1));echo $time' + ble/test "ble/util/conditional-sync 'sleep 10' '((time<1000))' 100" \ + stdout={1..10}00 + ble/test "ble/util/conditional-sync 'sleep 10' '((time<1000))' 100 progressive-weight" \ + stdout={1,3,7,15,31,63,{1..10}27} + ble/function#pop ble/util/msleep +) +( + ble/test ":| ble/util/cat | cat -A" stdout= + ble/test "printf a | ble/util/cat | cat -A" stdout=a + ble/test "printf '\0' | ble/util/cat | cat -A" stdout=^@ + ble/test "printf 'hello\nworld\n'| ble/util/cat | cat -A" stdout={hello\$,world\$} + ble/test "printf 'hello\nworld'| ble/util/cat | cat -A" stdout={hello\$,world} + ble/test "printf 'hello\0world\0'| ble/util/cat | cat -A" stdout=hello^@world^@ + ble/test "printf 'hello\0world'| ble/util/cat | cat -A" stdout=hello^@world +) +( + bleopt_pager=xxx PAGER=yyy + ble/test 'ble/util/get-pager ret' ret=xxx + bleopt_pager=xxx PAGER= + ble/test 'ble/util/get-pager ret' ret=xxx + bleopt_pager= PAGER=yyy + ble/test 'ble/util/get-pager ret' ret=yyy + bleopt_pager= PAGER= + ble/test 'ble/util/get-pager ret' ret=less +) +( + bleopt_pager=cat + ble/test 'ble/util/pager <<< hello' stdout=hello +) +( + ble/util/buffer.clear + ble/test 'ble/util/buffer.flush' stdout= + ble/util/buffer hello + ble/util/buffer world + ble/test 'ble/util/buffer.flush' stdout=helloworld + ble/test 'ble/util/buffer.flush' stdout= + ble/util/buffer.print hello + ble/util/buffer.print world + ble/test 'ble/util/buffer.flush' stdout={hello,world} + ble/test 'ble/util/buffer.flush' stdout= + ble/util/buffer.print hello + ble/util/buffer.print world + ble/util/buffer.clear + ble/test 'ble/util/buffer.flush' stdout= +) +( + ubeg=3 uend=10 uend0=5 + beg=0 end=5 end0=3 + ble/dirty-range#load --prefix=u + ble/test 'echo "$beg:$end:$end0"' stdout=3:10:5 + ubeg=3 uend=10 uend0=5 + ble/dirty-range#clear --prefix=u + ble/test 'echo "$ubeg:$uend:$uend0"' stdout=-1:-1:-1 + ble/dirty-range#update --prefix=u 0 5 2 + ble/test 'echo "$ubeg:$uend:$uend0"' stdout=0:5:2 + ble/dirty-range#update --prefix=u 10 10 12 + ble/test 'echo "$ubeg:$uend:$uend0"' stdout=0:10:9 + ble/dirty-range#clear --prefix=u + ble/dirty-range#update --prefix=u 2 2 3 + ble/dirty-range#update --prefix=u 2 2 3 + ble/test 'echo "$ubeg:$uend:$uend0"' stdout=2:2:4 + ble/dirty-range#clear --prefix=u + ble/dirty-range#update --prefix=u 1 5 3 + ble/dirty-range#update --prefix=u 7 11 9 + ble/test 'echo "$ubeg:$uend:$uend0"' stdout=1:11:7 + ble/dirty-range#clear --prefix=u + ble/dirty-range#update --prefix=u 1 7 5 + ble/dirty-range#update --prefix=u 4 15 11 + ble/test 'echo "$ubeg:$uend:$uend0"' stdout=1:15:9 + ble/dirty-range#clear --prefix=u + ble/dirty-range#update --prefix=u 1 7 5 + ble/dirty-range#update --prefix=u 3 4 5 + ble/test 'echo "$ubeg:$uend:$uend0"' stdout=1:6:5 + ble/dirty-range#clear --prefix=u + ble/dirty-range#update --prefix=u 4 8 6 + ble/dirty-range#update --prefix=u 2 8 10 + ble/test 'echo "$ubeg:$uend:$uend0"' stdout=2:8:8 + ble/dirty-range#clear --prefix=u + ble/dirty-range#update --prefix=u 6 12 8 + ble/dirty-range#update --prefix=u 3 7 8 + ble/test 'echo "$ubeg:$uend:$uend0"' stdout=3:11:8 + ble/dirty-range#clear --prefix=u + ble/dirty-range#update --prefix=u 10 13 11 + ble/dirty-range#update --prefix=u 3 7 8 + ble/test 'echo "$ubeg:$uend:$uend0"' stdout=3:12:11 +) +( + ble/test $'ble/util/s2c "\n"' ret=10 + ble/test 'ble/util/c2s 10' ret=$'\n' + ble/test $'ble/util/s2c "\x1b"' ret=27 + ble/test 'ble/util/c2s 27' ret=$'\x1b' + ble/test $'ble/util/s2c "\x1F"' ret=31 + ble/test 'ble/util/c2s 31' ret=$'\x1F' + c=$'\x7F' ble/test 'ble/util/s2c $c' ret=127 # bash-3.0 bug WA + ble/test 'ble/util/c2s 127' ret=$'\x7F' + ble/test 'ble/util/s2c " "' ret=32 + ble/test 'ble/util/c2s 32' ret=' ' + ble/test 'ble/util/s2c a' ret=97 + ble/test 'ble/util/c2s 97' ret=a + ble/test 'ble/util/s2c μ' ret=956 + ble/test 'ble/util/c2s 956' ret=μ + ble/test 'ble/util/s2c あ' ret=12354 + ble/test 'ble/util/c2s 12354' ret=あ + ble/test 'ble/util/s2c' ret=0 + ble/test 'ble/util/s2c abc' ret=97 + ble/test 'ble/util/s2c μν' ret=956 + ble/test 'ble/util/s2c あいう' ret=12354 + ble/test 'ble/util/c2s.cached 32' ret=' ' + ble/test 'ble/util/c2s.cached 97' ret=a + ble/test 'ble/util/c2s.cached 956' ret=μ + ble/test 'ble/util/c2s.cached 12354' ret=あ + LANG=C + ble/test 'ble/util/c2s 97' ret=a + ble/test 'ble/util/c2s 956; [[ $ret != μ ]]' + ble/test 'ble/util/c2s 12354; [[ $ret != あ ]]' +) +( + ble/test 'ble/util/c2bc 97' ret=1 + ble/test 'ble/util/c2bc 956' ret=2 + ble/test 'ble/util/c2bc 12354' ret=3 + ble/test 'ble/util/c2bc 0' ret=1 + ble/test 'ble/util/c2bc 127' ret=1 + ble/test 'ble/util/c2bc 128' ret=2 + ble/test 'ble/util/c2bc 2047' ret=2 + ble/test 'ble/util/c2bc 2048' ret=3 + ble/test 'ble/util/c2bc 65535' ret=3 + ble/test 'ble/util/c2bc 65536' ret=4 +) +( + ble/test 'ble/util/s2chars AaBbCc; ret="${ret[*]}"' ret='65 97 66 98 67 99' + ble/test 'ble/util/chars2s 65 97 66 98 67 99' ret=AaBbCc + ble/test 'ble/util/s2chars あいう; ret="${ret[*]}"' ret='12354 12356 12358' + ble/test 'ble/util/chars2s 12354 12356 12358' ret=あいう + ble/test 'ble/util/s2chars; ret="${ret[*]}"' ret= + ble/test 'ble/util/s2chars 0; ret="${ret[*]}"' ret=48 + ble/test 'ble/util/s2chars a; ret="${ret[*]}"' ret=97 + ble/test 'ble/util/s2chars μ; ret="${ret[*]}"' ret=956 + ble/test 'ble/util/s2chars あ; ret="${ret[*]}"' ret=12354 + ble/test 'ble/util/chars2s' ret= + ble/test 'ble/util/chars2s 48' ret=0 + ble/test 'ble/util/chars2s 97' ret=a + ble/test 'ble/util/chars2s 956' ret=μ + ble/test 'ble/util/chars2s 12354' ret=あ +) +( + check1() { + local char=$1 keyseq=$2 + ble/test "ble/util/c2keyseq $char" ret="$keyseq" + ble/test "ble/util/chars2keyseq $char" ret="$keyseq" + ble/test "ble/util/keyseq2chars '$keyseq'; ret=\"\${ret[*]}\"" ret="${3:-$char}" + ble/test "ble/util/chars2keyseq 98 $char 99" ret="b${keyseq}c" + ble/test "ble/util/keyseq2chars 'b${keyseq}c'; ret=\"\${ret[*]}\"" ret="98 ${3:-$char} 99" + } + check1 '7' '\a' + check1 '8' '\b' + check1 '9' '\t' + check1 '10' '\n' + check1 '11' '\v' + check1 '12' '\f' + check1 '13' '\r' + check1 '27' '\e' + check1 '127' '\d' + check1 '92' '\\' + check1 '28' '\x1c' # workaround bashbug \C-\, \C-\\ + check1 '156' '\x9c' # workaround bashbug \C-\, \C-\\ + check1 '0' '\C-@' + check1 '1' '\C-a' + check1 '26' '\C-z' + check1 '29' '\C-]' + check1 '30' '\C-^' + check1 '31' '\C-_' + check1 '128' '\M-\C-@' '27 0' + check1 '64' '@' + check1 '97' 'a' + check1 '956' 'μ' + check1 '12354' 'あ' + ble/test ble/util/c2keyseq ret='\C-@' + ble/test ble/util/chars2keyseq ret= + ble/test ble/util/keyseq2chars ret= +) +( + function pack { ret="${bytes[*]}"; } + ble/test 'ble/encoding:UTF-8/b2c ' ret=0 + ble/test 'ble/encoding:UTF-8/b2c 97' ret=97 + ble/test 'ble/encoding:UTF-8/b2c 97 98 99 99' ret=97 + ble/test 'ble/encoding:UTF-8/b2c 206 188 99 99' ret=956 + ble/test 'ble/encoding:UTF-8/b2c 227 129 130 99' ret=12354 + ble/test 'ble/encoding:UTF-8/c2b 97 ; pack' ret=97 + ble/test 'ble/encoding:UTF-8/c2b 956 ; pack' ret='206 188' + ble/test 'ble/encoding:UTF-8/c2b 12354; pack' ret='227 129 130' + ble/test 'ble/encoding:UTF-8/c2b ; pack' ret=0 + ble/test 'ble/encoding:UTF-8/c2b 0 ; pack' ret=0 + ble/test 'ble/encoding:UTF-8/c2b 127 ; pack' ret=127 + ble/test 'ble/encoding:UTF-8/c2b 128 ; pack' ret='194 128' + ble/test 'ble/encoding:UTF-8/c2b 2047; pack' ret='223 191' + ble/test 'ble/encoding:UTF-8/c2b 2048; pack' ret='224 160 128' +) +( + function pack { ret="${bytes[*]}"; } + ble/test 'ble/encoding:C/b2c ' ret=0 + ble/test 'ble/encoding:C/b2c 97' ret=97 + ble/test 'ble/encoding:C/b2c 97 98 99 99' ret=97 + ble/test 'ble/encoding:C/b2c 206 188 99 99' ret=206 + ble/test 'ble/encoding:C/b2c 227 129 130 99' ret=227 + ble/test 'ble/encoding:C/b2c 97 ' ret=97 + ble/test 'ble/encoding:C/b2c 956 ' ret=188 + ble/test 'ble/encoding:C/b2c 12354 ' ret=66 + ble/test 'ble/encoding:C/c2b ; pack' ret=0 + ble/test 'ble/encoding:C/c2b 0 ; pack' ret=0 + ble/test 'ble/encoding:C/c2b 127 ; pack' ret=127 + ble/test 'ble/encoding:C/c2b 128 ; pack' ret=128 + ble/test 'ble/encoding:C/c2b 2047; pack' ret=255 + ble/test 'ble/encoding:C/c2b 2048; pack' ret=0 +) +( + clear-locale() { LC_ALL= LANG= LC_CTYPE=; } + for lang in {C,en_US,ja{_JP,}}.{UTF-8,utf8} ja_JP.{utf8,UTF-8}@cjk{wide,narrow,single}; do + clear-locale + ble/test "LANG=$lang; ble/util/is-unicode-output" + clear-locale + ble/test "LANG=C LC_CTYPE=$lang; ble/util/is-unicode-output" + clear-locale + ble/test "LC_CTYPE=C LANG=C LC_ALL=$lang; ble/util/is-unicode-output" + done + for lang in '' C POSIX UTF-8 utf8 ja_JP.eucJP; do + clear-locale + ble/test "LANG=$lang; ble/util/is-unicode-output" exit=1 + clear-locale + ble/test "LANG=C LC_CTYPE=$lang; ble/util/is-unicode-output" exit=1 + clear-locale + ble/test "LC_CTYPE=C LANG=C LC_ALL=$lang; ble/util/is-unicode-output" exit=1 + done +) +ble/test/end-section diff --git a/.local/src/blesh/lib/vim-airline.sh b/.local/src/blesh/lib/vim-airline.sh new file mode 100644 index 0000000..b4d8b6e --- /dev/null +++ b/.local/src/blesh/lib/vim-airline.sh @@ -0,0 +1,306 @@ +# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license +ble-import keymap/vi +ble-import prompt-git +bleopt/declare -n vim_airline_theme dark +function bleopt/check:vim_airline_theme { + local init=ble/lib/vim-airline/theme:"$value"/initialize + if ! ble/is-function "$init"; then + local ret + if ! ble/util/import/search "airline/$value"; then + ble/util/print "ble/lib/vim-airline: theme '$value' not found." >&2 + return 1 + fi + ble/util/import "$ret" + ble/is-function "$init" || return 1 + fi + "$init" + return 0 +} +bleopt/declare -v vim_airline_section_a '\e[1m\q{lib/vim-airline/mode}' +bleopt/declare -v vim_airline_section_b '\q{lib/vim-airline/gitstatus}' +bleopt/declare -v vim_airline_section_c '\w' +bleopt/declare -v vim_airline_section_x 'bash' +bleopt/declare -v vim_airline_section_y '$_ble_util_locale_encoding[unix]' +bleopt/declare -v vim_airline_section_z ' \q{history-percentile} \e[1m!\q{history-index}/\!\e[22m \q{position}' +bleopt/declare -v vim_airline_left_sep $'\uE0B0' +bleopt/declare -v vim_airline_left_alt_sep $'\uE0B1' +bleopt/declare -v vim_airline_right_sep $'\uE0B2' +bleopt/declare -v vim_airline_right_alt_sep $'\uE0B3' +bleopt/declare -v vim_airline_symbol_branch $'\uE0A0' +bleopt/declare -v vim_airline_symbol_dirty $'\u26A1' +function bleopt/check:vim_airline_left_sep { ble/prompt/unit#clear _ble_prompt_status; } +function bleopt/check:vim_airline_left_alt_sep { ble/prompt/unit#clear _ble_prompt_status; } +function bleopt/check:vim_airline_right_sep { ble/prompt/unit#clear _ble_prompt_status; } +function bleopt/check:vim_airline_right_alt_sep { ble/prompt/unit#clear _ble_prompt_status; } +builtin eval -- "${_ble_util_gdict_declare//NAME/_ble_lib_vim_airline_mode_map_default}" +ble/gdict#set _ble_lib_vim_airline_mode_map_default 'i' 'INSERT' +ble/gdict#set _ble_lib_vim_airline_mode_map_default 'n' 'NORMAL' +ble/gdict#set _ble_lib_vim_airline_mode_map_default 'in' '(INSERT)' +ble/gdict#set _ble_lib_vim_airline_mode_map_default 'o' 'OP PENDING' +ble/gdict#set _ble_lib_vim_airline_mode_map_default 'R' 'REPLACE' +ble/gdict#set _ble_lib_vim_airline_mode_map_default '' 'V REPLACE' +ble/gdict#set _ble_lib_vim_airline_mode_map_default 'v' 'VISUAL' +ble/gdict#set _ble_lib_vim_airline_mode_map_default 'V' 'V-LINE' +ble/gdict#set _ble_lib_vim_airline_mode_map_default '' 'V-BLOCK' +ble/gdict#set _ble_lib_vim_airline_mode_map_default 's' 'SELECT' +ble/gdict#set _ble_lib_vim_airline_mode_map_default 'S' 'S-LINE' +ble/gdict#set _ble_lib_vim_airline_mode_map_default '' 'S-BLOCK' +ble/gdict#set _ble_lib_vim_airline_mode_map_default '?' '------' +ble/gdict#set _ble_lib_vim_airline_mode_map_default 'c' 'COMMAND' +builtin eval -- "${_ble_util_gdict_declare//NAME/_ble_lib_vim_airline_mode_map_atomic}" +ble/gdict#set _ble_lib_vim_airline_mode_map_atomic 'i' 'I' +ble/gdict#set _ble_lib_vim_airline_mode_map_atomic 'n' 'N' +ble/gdict#set _ble_lib_vim_airline_mode_map_atomic 'R' 'R' +ble/gdict#set _ble_lib_vim_airline_mode_map_atomic 'v' 'V' +ble/gdict#set _ble_lib_vim_airline_mode_map_atomic 'V' 'V-L' +ble/gdict#set _ble_lib_vim_airline_mode_map_atomic '' 'V-B' +ble/gdict#set _ble_lib_vim_airline_mode_map_atomic 's' 'S' +ble/gdict#set _ble_lib_vim_airline_mode_map_atomic 'S' 'S-L' +ble/gdict#set _ble_lib_vim_airline_mode_map_atomic '' 'S-B' +ble/gdict#set _ble_lib_vim_airline_mode_map_atomic '?' '--' +ble/gdict#set _ble_lib_vim_airline_mode_map_atomic 'c' 'C' +builtin eval -- "${_ble_util_gdict_declare//NAME/_ble_lib_vim_airline_mode_map}" +ble/gdict#cp _ble_lib_vim_airline_mode_map_default _ble_lib_vim_airline_mode_map +function ble/lib/vim-airline/initialize-faces { + ble/color/defface vim_airline_a fg=17,bg=45 + ble/color/defface vim_airline_b fg=231,bg=27 + ble/color/defface vim_airline_c fg=231,bg=18 + ble/color/defface vim_airline_error fg=16,bg=88 # fg=#000000,bg=#990000 + ble/color/defface vim_airline_term fg=158,bg=234 # fg=#9cffd3,bg=#202020 + ble/color/defface vim_airline_warning fg=16,bg=166 # fg=#000000,bg=#df5f00 + local section map + for section in a b c error term warning; do + for map in _normal _insert _visual _commandline _inactive; do + ble/color/defface "vim_airline_$section$map" ref:"vim_airline_$section" + done + ble/color/defface "vim_airline_${section}_replace" ref:"vim_airline_${section}_insert" + done + local map + for map in '' _normal _insert _replace _visual _commandline _inactive; do + ble/color/defface "vim_airline_x$map" ref:"vim_airline_c$map" + ble/color/defface "vim_airline_y$map" ref:"vim_airline_b$map" + ble/color/defface "vim_airline_z$map" ref:"vim_airline_a$map" + done + local name + for name in {a,b,c,x,y,z,error,term,warning}{,_normal,_insert,_replace,_visual,_commandline,_inactive}; do + ble/color/defface "vim_airline_${name}_modified" ref:"vim_airline_$name" + done +} +ble/lib/vim-airline/initialize-faces +function ble/lib/vim-airline/convert-theme/.to-color256 { + local R=$((16#${1:1:2})) + local G=$((16#${1:3:2})) + local B=$((16#${1:5:2})) + ble/color/convert-rgb24-to-color256 "$R" "$G" "$B" +} +function ble/lib/vim-airline/convert-theme/.setface { + local gspec= + local ret + ble/lib/vim-airline/convert-theme/.to-color256 "$2"; local fg=$ret + ble/lib/vim-airline/convert-theme/.to-color256 "$3"; local bg=$ret + printf 'ble/color/setface vim_airline_%-13s %-13s # %s\n' "$1" "fg=$fg,bg=$bg" "fg=$2,bg=$3" +} +function ble/lib/vim-airline/convert-theme { + local file=$1 + sed -n 's/let s:airline_\([a-zA-Z_0-9]\{1,\}\)[^[:alnum:]]\{1,\}\(\#[0-9a-fA-F]\{6\}\)[^[:alnum:]]\{1,\}\(\#[0-9a-fA-F]\{6\}\).*/\1 \2 \3/p' "$file" | + while builtin read -r face fg bg; do + ble/lib/vim-airline/convert-theme/.setface "$face" "$fg" "$bg" + done +} +ble/color/setface vim_airline_a_normal fg=17,bg=190 # fg=#00005f,bg=#dfff00 +ble/color/setface vim_airline_b_normal fg=231,bg=238 # fg=#ffffff,bg=#444444 +ble/color/setface vim_airline_c_normal fg=158,bg=234 # fg=#9cffd3,bg=#202020 +ble/color/setface vim_airline_a_insert fg=17,bg=45 # fg=#00005f,bg=#00dfff +ble/color/setface vim_airline_b_insert fg=231,bg=27 # fg=#ffffff,bg=#005fff +ble/color/setface vim_airline_c_insert fg=231,bg=18 # fg=#ffffff,bg=#000080 +ble/color/setface vim_airline_a_visual fg=16,bg=214 # fg=#000000,bg=#ffaf00 +ble/color/setface vim_airline_b_visual fg=16,bg=202 # fg=#000000,bg=#ff5f00 +ble/color/setface vim_airline_c_visual fg=231,bg=52 # fg=#ffffff,bg=#5f0000 +ble/color/setface vim_airline_a_inactive fg=239,bg=234 # fg=#4e4e4e,bg=#1c1c1c +ble/color/setface vim_airline_b_inactive fg=239,bg=235 # fg=#4e4e4e,bg=#262626 +ble/color/setface vim_airline_c_inactive fg=239,bg=236 # fg=#4e4e4e,bg=#303030 +ble/color/setface vim_airline_a_commandline fg=17,bg=40 # fg=#00005f,bg=#00d700 +ble/color/setface vim_airline_b_commandline fg=231,bg=238 # fg=#ffffff,bg=#444444 +ble/color/setface vim_airline_c_commandline fg=158,bg=234 # fg=#9cffd3,bg=#202020 +_ble_lib_vim_airline_mode_data=() +_ble_lib_vim_airline_keymap= +_ble_lib_vim_airline_mode= +_ble_lib_vim_airline_rawmode= +function ble/prompt/unit:_ble_lib_vim_airline_mode/update { + local keymap mode m + ble/keymap:vi/script/get-vi-keymap + ble/keymap:vi/script/get-mode + case $mode in + (i*) m='insert' ;; + ([R]*) m='replace' ;; + (*[vVsS]) m='visual' ;; + (*c) m='commandline' ;; + (*n) m='normal' ;; + (*) m='inactive' ;; + esac + ble/prompt/unit/add-hash '$_ble_edit_str' + ble/prompt/unit/add-hash '$_ble_history_INDEX' + local entry + ble/history/get-entry "$_ble_history_INDEX" + [[ $_ble_edit_str != "$entry" ]] && m=${m}_modified + ble/prompt/unit/assign _ble_lib_vim_airline_keymap "$keymap" + ble/prompt/unit/assign _ble_lib_vim_airline_mode "$m" + ble/prompt/unit/assign _ble_lib_vim_airline_rawmode "$mode" + [[ $prompt_unit_changed ]] +} +function ble/prompt/backslash:lib/vim-airline/mode/.resolve { + local raw=$1 + if ble/gdict#has _ble_lib_vim_airline_mode_map "$raw"; then + ble/gdict#get _ble_lib_vim_airline_mode_map "$raw" + else + case $raw in + (o) ble/prompt/backslash:lib/vim-airline/mode/.resolve "$_ble_lib_vim_airline_rawmode" ;; + ([iR]?*) ble/prompt/backslash:lib/vim-airline/mode/.resolve "${raw::1}" ;; + (*?[ncvVsS]) ble/prompt/backslash:lib/vim-airline/mode/.resolve "${raw:${#raw}-1}" ;; + () ble/prompt/backslash:lib/vim-airline/mode/.resolve R ;; + (R) ble/prompt/backslash:lib/vim-airline/mode/.resolve i ;; + ([S]) ble/prompt/backslash:lib/vim-airline/mode/.resolve s ;; + ([Vs]) ble/prompt/backslash:lib/vim-airline/mode/.resolve v ;; + ([ivnc]) + ret= + case $_ble_lib_vim_airline_rawmode in + (i*) ret=$bleopt_keymap_vi_mode_name_insert ;; + (R*) ret=$bleopt_keymap_vi_mode_name_replace ;; + (*) ret=$bleopt_keymap_vi_mode_name_vreplace ;; + esac + [[ $_ble_lib_vim_airline_rawmode == [iR]?* ]] && + ble/string#tolower "($insert) " + case $_ble_lib_vim_airline_rawmode in + (*n) + if [[ ! $ret ]]; then + local rex='[[:alnum:]](.*[[:alnum:]])?' + [[ $bleopt_keymap_vi_mode_string_nmap =~ $rex ]] + ret=${BASH_REMATCH[0]:-NORMAL} + fi ;; + (*v) ret="${ret}${ret:+ }$bleopt_keymap_vi_mode_name_visual" ;; + (*V) ret="${ret}${ret:+ }$bleopt_keymap_vi_mode_name_visual $bleopt_keymap_vi_mode_name_line" ;; + (*) ret="${ret}${ret:+ }$bleopt_keymap_vi_mode_name_visual $bleopt_keymap_vi_mode_name_block" ;; + (*s) ret="${ret}${ret:+ }$bleopt_keymap_vi_mode_name_select" ;; + (*S) ret="${ret}${ret:+ }$bleopt_keymap_vi_mode_name_select $bleopt_keymap_vi_mode_name_line" ;; + (*) ret="${ret}${ret:+ }$bleopt_keymap_vi_mode_name_select $bleopt_keymap_vi_mode_name_block" ;; + (*c) ret="${ret}${ret:+ }COMMAND" ;; + esac + [[ $ret ]] || + ble/prompt/backslash:lib/vim-airline/mode/.resolve '?' ;; + (*) ret='?__' ;; + esac + fi +} +function ble/prompt/backslash:lib/vim-airline/mode { + local ret + if [[ $_ble_lib_vim_airline_keymap == vi_omap ]]; then + ble/prompt/backslash:lib/vim-airline/mode/.resolve o + else + ble/prompt/backslash:lib/vim-airline/mode/.resolve "$_ble_lib_vim_airline_rawmode" + fi + [[ $ret ]] && ble/prompt/print "$ret" +} +function ble/prompt/backslash:lib/vim-airline/gitstatus { + local "${_ble_contrib_prompt_git_vars[@]/%/=}" # WA #D1570 checked + if ble/contrib/prompt-git/initialize; then + local hash branch + ble/contrib/prompt-git/get-head-information + if [[ $branch ]]; then + ble/prompt/print "$bleopt_vim_airline_symbol_branch$branch" + elif [[ $hash ]]; then + ble/prompt/print "$bleopt_vim_airline_symbol_branch${hash::7}" + else + ble/prompt/print '$bleopt_vim_airline_symbol_branch???????' + fi + ble/contrib/prompt-git/is-dirty && + ble/prompt/print "$bleopt_vim_airline_symbol_dirty" + fi +} +function ble/prompt/unit:{vim-airline-section}/update { + local section=$1 + local ref_ps=bleopt_vim_airline_section_$section + local face=vim_airline_${section}_$_ble_lib_vim_airline_mode + local prefix=_ble_lib_vim_airline_section_$section + ble/prompt/unit/add-hash '$_ble_lib_vim_airline_mode_data' + ble/prompt/unit/add-hash "\$$ref_ps" + local trace_opts=confine:relative:noscrc:face0="$face":ansi:measure-bbox:measure-gbox + local prompt_rows=1 prompt_cols=$cols # Note: cols は \q{lib/vim-airline} で設定される + ble/prompt/unit:{section}/update "$prefix" "${!ref_ps}" "$trace_opts" +} +function ble/prompt/unit:_ble_lib_vim_airline_section_a/update { ble/prompt/unit:{vim-airline-section}/update a; } +function ble/prompt/unit:_ble_lib_vim_airline_section_b/update { ble/prompt/unit:{vim-airline-section}/update b; } +function ble/prompt/unit:_ble_lib_vim_airline_section_c/update { ble/prompt/unit:{vim-airline-section}/update c; } +function ble/prompt/unit:_ble_lib_vim_airline_section_x/update { ble/prompt/unit:{vim-airline-section}/update x; } +function ble/prompt/unit:_ble_lib_vim_airline_section_y/update { ble/prompt/unit:{vim-airline-section}/update y; } +function ble/prompt/unit:_ble_lib_vim_airline_section_z/update { ble/prompt/unit:{vim-airline-section}/update z; } +function ble/lib/vim-airline/.print-section { + local section=$1 + local ret g0 bg + ble/color/face2g "vim_airline_${section}_$_ble_lib_vim_airline_mode"; g0=$ret + ble/color/g#compute-bg "$g0"; bg=$ret + if [[ $prev_g0 ]]; then + local sep=bleopt_vim_airline gsep + if [[ $prev_section == [ab] ]]; then + sep=${sep}_left + else + sep=${sep}_right + fi + if [[ $prev_bg == $bg ]]; then + sep=${sep}_alt_sep + if [[ $prev_section == [ab] ]]; then + gsep=$prev_g0 + else + gsep=$g0 + fi + ((gsep&=~_ble_color_gflags_DecorationMask|_ble_color_gflags_Revert|_ble_color_gflags_Invisible)) + else + sep=${sep}_sep gsep=0 + if [[ $sep == *_right_sep ]]; then + ble/color/g#setfg gsep "$bg" + ble/color/g#setbg gsep "$prev_bg" + else + ble/color/g#setfg gsep "$prev_bg" + ble/color/g#setbg gsep "$bg" + fi + fi + ble/color/g2sgr-ansi "$gsep" + ble/prompt/print "$ret${!sep}" + fi + local ref_show=_ble_lib_vim_airline_section_${section}_show + if [[ ${!ref_show} ]]; then + ble/prompt/unit:{section}/get "_ble_lib_vim_airline_section_$section"; local esc=$ret + ble/color/g2sgr-ansi "$g0" + ble/prompt/print "$ret $esc$ret " + fi + [[ $section == c ]] && ble/prompt/print $'\r' + prev_g0=$g0 + prev_bg=$bg + prev_section=$section +} +function ble/prompt/backslash:lib/vim-airline { + local "${_ble_contrib_prompt_git_vars[@]/%/=}" # WA #D1570 checked + ble/prompt/unit#update _ble_lib_vim_airline_mode + local ret bg=0 + ble/color/face2g "vim_airline_c_$_ble_lib_vim_airline_mode" + ble/color/g#getbg "$ret" + ble/color/g#setbg bg "$ret" + ble/color/setface prompt_status_line "g:$bg" + local cols=$COLUMNS; ((_ble_term_xenl||cols--)) + local unit rest_cols=$((cols-4)) + for unit in _ble_lib_vim_airline_section_{a,c,z,b,y,x}; do + ble/prompt/unit#update "$unit" + local gx1=${unit}_gbox[0]; gx1=${!gx1} + local x2=${unit}_bbox[2]; x2=${!x2} + local show= + [[ $gx1 ]] && ((x2+2<=rest_cols)) && ((show=1,rest_cols-=x2+2)) + builtin eval -- "${unit}_show=\$show" + done + local section prev_section= prev_g0= prev_bg= + for section in a b c x y z; do + ble/lib/vim-airline/.print-section "$section" + done +} +bleopt -I vim_airline_@ +bleopt keymap_vi_mode_show= +bleopt prompt_status_line='\q{lib/vim-airline}' +bleopt prompt_status_align=$'justify=\r' diff --git a/.local/src/blesh/lib/vim-arpeggio.sh b/.local/src/blesh/lib/vim-arpeggio.sh new file mode 100644 index 0000000..cb59766 --- /dev/null +++ b/.local/src/blesh/lib/vim-arpeggio.sh @@ -0,0 +1,48 @@ +# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license +source "$_ble_base/keymap/vi.sh" +bleopt/declare -v vim_arpeggio_timeoutlen 40 +function ble/lib/vim-arpeggio.sh/bind/.usage { + ble/util/print "usage: ble/lib/vim-arpeggio.sh/bind [-m KEYMAP] -[fxcs@] KEYS COMMAND" + ble/util/print " KEYS has the form of {mods}{X}{Y}. {mods} are modifiers of the form" + ble/util/print " /([CSMAsH]-)*/ and {X} and {Y} are alphabets which specify simultaneous" + ble/util/print " keys." +} +function ble/lib/vim-arpeggio.sh/bind { + local -a opts=() + if [[ $1 == -m ]]; then + if [[ ! $2 ]]; then + ble/util/print "vim-arpeggio.sh: invalid option argument for \`-m'." >&2 + ble/lib/vim-arpeggio.sh/bind/.usage >&2 + return 1 + fi + ble/array#push opts -m "$2" + shift 2 + fi + local type=$1 keys=$2 cmd=$3 + if [[ $type == --help ]]; then + ble/lib/vim-arpeggio.sh/bind/.usage + return 0 + elif [[ $type != -[fxcs@] ]]; then + ble/util/print "vim-arpeggio.sh: invalid bind type." >&2 + ble/lib/vim-arpeggio.sh/bind/.usage >&2 + return 1 + fi + local mods= + if local rex='^(([CSMAsH]-)+)..'; [[ $keys =~ $rex ]]; then + mods=${BASH_REMATCH[1]} + keys=${keys:${#mods}} + fi + local timeout=$((bleopt_vim_arpeggio_timeoutlen)) + ((timeout<0)) && timeout= + if ((${#keys}==2)); then + local k1=$mods${keys::1} k2=$mods${keys:1:1} + ble-bind "${opts[@]}" "$type" "$k1 $k2" "$cmd" + ble-bind "${opts[@]}" "$type" "$k2 $k1" "$cmd" + ble-bind "${opts[@]}" -T "$k1" "$timeout" + ble-bind "${opts[@]}" -T "$k2" "$timeout" + else + ble/util/print "vim-arpeggio.sh: sorry only 2-key bindings are supported now." >&2 + ble/lib/vim-arpeggio.sh/bind/.usage >&2 + return 1 + fi +} diff --git a/.local/src/blesh/lib/vim-surround.sh b/.local/src/blesh/lib/vim-surround.sh new file mode 100644 index 0000000..fc5002c --- /dev/null +++ b/.local/src/blesh/lib/vim-surround.sh @@ -0,0 +1,551 @@ +# this script is a part of blesh (https://github.com/akinomyoga/ble.sh) under BSD-3-Clause license +source "$_ble_base/keymap/vi.sh" +bleopt/declare -n vim_surround_45 $'$(\r)' # ysiw- +bleopt/declare -n vim_surround_61 $'$((\r))' # ysiw= +bleopt/declare -n vim_surround_q \" # ysiwQ +bleopt/declare -n vim_surround_Q \' # ysiwq +bleopt/declare -v vim_surround_omap_bind 1 +function ble/lib/vim-surround.sh/get-char-from-key { + local key=$1 + if ! ble-decode-key/ischar "$key"; then + local flag=$((key&_ble_decode_MaskFlag)) code=$((key&_ble_decode_MaskChar)) + if ((flag==_ble_decode_Ctrl&&63<=code&&code<128&&(code&0x1F)!=0)); then + ((key=code==63?127:code&0x1F)) + else + return 1 + fi + fi + ble/util/c2s "$key" + return 0 +} +function ble/lib/vim-surround.sh/async-inputtarget.hook { + local mode=$1 hook=${@:2:$#-2} key=${@:$#} ret + if ! ble/lib/vim-surround.sh/get-char-from-key "$key"; then + ble/widget/vi-command/bell + return 1 + fi + local c=$ret + if [[ :$mode: == *:digit:* && $c == [0-9] ]]; then + _ble_edit_arg=$_ble_edit_arg$c + _ble_decode_key__hook="ble/lib/vim-surround.sh/async-inputtarget.hook digit $hook" + return 147 + elif [[ :$mode: == *:init:* && $c == ' ' ]]; then + _ble_decode_key__hook="ble/lib/vim-surround.sh/async-inputtarget.hook space $hook" + return 147 + fi + if [[ $c == [$'\e\003'] ]]; then # C-[, C-c + ble/widget/vi-command/bell + return 1 + else + [[ $c == \' ]] && c="'\''" + [[ $mode == space ]] && c=' '$c + builtin eval -- "$hook '$c'" + fi +} +function ble/lib/vim-surround.sh/async-inputtarget { + local IFS=$_ble_term_IFS + _ble_decode_key__hook="ble/lib/vim-surround.sh/async-inputtarget.hook init:digit $*" + return 147 +} +function ble/lib/vim-surround.sh/async-inputtarget-noarg { + local IFS=$_ble_term_IFS + _ble_decode_key__hook="ble/lib/vim-surround.sh/async-inputtarget.hook init $*" + return 147 +} +_ble_lib_vim_surround_previous_tag=html +function ble/lib/vim-surround.sh/load-template { + local ins=$1 + if [[ ${ins//[0-9]} && ! ${ins//[_0-9a-zA-Z]} ]]; then + local optname=bleopt_vim_surround_$ins + template=${!optname} + [[ $template ]] && return 0 + fi + local ret; ble/util/s2c "$ins" + local optname=bleopt_vim_surround_$ret + template=${!optname} + [[ $template ]] && return 0 + case "$ins" in + (['<tT']*) + local tag=${ins:1}; tag=${tag//$'\r'/' '} + if [[ ! $tag ]]; then + tag=$_ble_lib_vim_surround_previous_tag + else + tag=${tag%'>'} + _ble_lib_vim_surround_previous_tag=$tag + fi + local end_tag=${tag%%["$_ble_term_IFS"]*} + template="<$tag>"$'\r'"</$end_tag>" ;; + ('(') template=$'( \r )' ;; + ('[') template=$'[ \r ]' ;; + ('{') template=$'{ \r }' ;; + (['b)']) template=$'(\r)' ;; + (['r]']) template=$'[\r]' ;; + (['B}']) template=$'{\r}' ;; + (['a>']) template=$'<\r>' ;; + ([a-zA-Z]) return 1 ;; + (*) template=$ins ;; + esac +} &>/dev/null +function ble/lib/vim-surround.sh/surround { + local text=$1 ins=$2 opts=$3 + local instype= + [[ $ins == $'\x1D' ]] && ins='}' instype=indent # C-], C-} + local has_space= + [[ $ins == ' '?* ]] && ins=${ins:1} has_space=1 + local template= + ble/lib/vim-surround.sh/load-template "$ins" || return 1 + local prefix= suffix= + if [[ $template == *$'\r'* ]]; then + prefix=${template%%$'\r'*} + suffix=${template#*$'\r'} + else + prefix=$template + suffix=$template + fi + if [[ $prefix == *' ' && $suffix == ' '* ]]; then + prefix=${prefix::${#prefix}-1} + suffix=${suffix:1} + has_space=1 + fi + if [[ $instype == indent || :$opts: == *:linewise:* ]]; then + ble-edit/content/find-logical-bol "$beg"; local bol=$ret + ble-edit/content/find-non-space "$bol"; local nol=$ret + local indent= + if [[ $instype == indent ]] || ((bol<nol)); then + indent=${_ble_edit_str:bol:nol-bol} + elif [[ $has_space ]]; then + indent=' ' + fi + text=$indent$text + if [[ $instype == indent || :$opts: == *:indent:* ]]; then + ble/keymap:vi/string#increase-indent "$text" "$bleopt_indent_offset"; text=$ret + fi + text=$'\n'$text$'\n'$indent + elif [[ $has_space ]]; then + text=' '$text' ' + fi + ret=$prefix$text$suffix +} +function ble/lib/vim-surround.sh/async-read-tagname { + ble/keymap:vi/async-commandline-mode "$1" + _ble_edit_PS1='<' + _ble_keymap_vi_cmap_before_command=ble/lib/vim-surround.sh/async-read-tagname/.before-command.hook + return 147 +} +function ble/lib/vim-surround.sh/async-read-tagname/.before-command.hook { + if [[ ${KEYS[0]} == 62 ]]; then # '>' + ble/widget/self-insert + ble/widget/vi_cmap/accept + ble/decode/widget/suppress-widget + fi +} +_ble_lib_vim_surround_ys_type= # ys | yS | vS | vgS +_ble_lib_vim_surround_ys_args=() +_ble_lib_vim_surround_ys_ranges=() +function ble/highlight/layer:region/mark:vi_surround/get-selection { + local type=$_ble_lib_vim_surround_ys_type + local context=${_ble_lib_vim_surround_ys_args[2]} + if [[ $context == block ]]; then + local -a sub_ranges + sub_ranges=("${_ble_lib_vim_surround_ys_ranges[@]}") + selection=() + local sub + for sub in "${sub_ranges[@]}"; do + ble/string#split sub : "$sub" + ((sub[0]<sub[1])) || continue + ble/array#push selection "${sub[0]}" "${sub[1]}" + done + else + selection=("${_ble_lib_vim_surround_ys_args[@]::2}") + if [[ $context == char && ( $type == yS || $type == ySS || $type == vgS ) ]]; then + local ret + ble-edit/content/find-logical-bol "${selection[0]}"; selection[0]=$ret + ble-edit/content/find-logical-eol "${selection[1]}"; selection[1]=$ret + fi + fi +} +function ble/highlight/layer:region/mark:vi_surround/get-face { + face=region_target +} +function ble/lib/vim-surround.sh/operator.impl { + _ble_lib_vim_surround_ys_type=$1; shift + _ble_lib_vim_surround_ys_args=("$@") + [[ $3 == block ]] && _ble_lib_vim_surround_ys_ranges=("${sub_ranges[@]}") + _ble_edit_mark_active=vi_surround + ble/lib/vim-surround.sh/async-inputtarget-noarg ble/widget/vim-surround.sh/ysurround.hook1 + ble/lib/vim-surround.sh/ysurround.repeat/entry + return 147 +} +function ble/keymap:vi/operator:yS { ble/lib/vim-surround.sh/operator.impl yS "$@"; } +function ble/keymap:vi/operator:ys { ble/lib/vim-surround.sh/operator.impl ys "$@"; } +function ble/keymap:vi/operator:ySS { ble/lib/vim-surround.sh/operator.impl ySS "$@"; } +function ble/keymap:vi/operator:yss { ble/lib/vim-surround.sh/operator.impl yss "$@"; } +function ble/keymap:vi/operator:vS { ble/lib/vim-surround.sh/operator.impl vS "$@"; } +function ble/keymap:vi/operator:vgS { ble/lib/vim-surround.sh/operator.impl vgS "$@"; } +function ble/widget/vim-surround.sh/ysurround.hook1 { + local ins=$1 + if local rex='^ ?[<tT]$'; [[ $ins =~ $rex ]]; then + ble/lib/vim-surround.sh/async-read-tagname "ble/widget/vim-surround.sh/ysurround.hook2 '$ins'" + else + ble/widget/vim-surround.sh/ysurround.core "$ins" + fi +} +function ble/widget/vim-surround.sh/ysurround.hook2 { + local ins=$1 tagName=$2 + ble/widget/vim-surround.sh/ysurround.core "$ins$tagName" +} +function ble/widget/vim-surround.sh/ysurround.core { + local ins=$1 + _ble_edit_mark_active= # mark:vi_surround を解除 + local ret + local type=$_ble_lib_vim_surround_ys_type + local beg=${_ble_lib_vim_surround_ys_args[0]} + local end=${_ble_lib_vim_surround_ys_args[1]} + local context=${_ble_lib_vim_surround_ys_args[2]} + local sub_ranges; sub_ranges=("${_ble_lib_vim_surround_ys_ranges[@]}") + _ble_lib_vim_surround_ys_type= + _ble_lib_vim_surround_ys_args=() + _ble_lib_vim_surround_ys_ranges=() + if [[ $context == block ]]; then + local isub=${#sub_ranges[@]} sub + local smin= smax= slpad= srpad= + while ((isub--)); do + local sub=${sub_ranges[isub]} + local stext=${sub#*:*:*:*:*:} + ble/string#split sub : "${sub::${#sub}-${#stext}}" + smin=${sub[0]} smax=${sub[1]} + slpad=${sub[2]} srpad=${sub[3]} + if ! ble/lib/vim-surround.sh/surround "$stext" "$ins"; then + ble/widget/vi-command/bell + return 1 + fi + stext=$ret + ((slpad)) && { ble/string#repeat ' ' "$slpad"; stext=$ret$stext; } + ((srpad)) && { ble/string#repeat ' ' "$srpad"; stext=$stext$ret; } + ble/widget/.replace-range "$smin" "$smax" "$stext" + done + else + local text=${_ble_edit_str:beg:end-beg} + if [[ $type == ys ]]; then + if local rex=$'[ \t\n]+$'; [[ $text =~ $rex ]]; then + ((end-=${#BASH_REMATCH})) + text=${_ble_edit_str:beg:end-beg} + fi + fi + local opts= + if [[ $type == yS || $type == ySS || $context == char && $type == vgS ]]; then + opts=linewise:indent + elif [[ $context == line ]]; then + opts=linewise + fi + if ! ble/lib/vim-surround.sh/surround "$text" "$ins" "$opts"; then + ble/widget/vi-command/bell + return 1 + fi + local text=$ret + ble/widget/.replace-range "$beg" "$end" "$text" + fi + _ble_edit_ind=$beg + if [[ $context == line ]]; then + ble/widget/vi-command/first-non-space + else + ble/keymap:vi/adjust-command-mode + fi + ble/keymap:vi/mark/end-edit-area + ble/lib/vim-surround.sh/ysurround.repeat/record "$type" "$ins" + return 0 +} +function ble/widget/vim-surround.sh/ysurround-current-line { + ble/widget/vi_nmap/linewise-operator yss +} +function ble/widget/vim-surround.sh/ySurround-current-line { + ble/widget/vi_nmap/linewise-operator ySS +} +function ble/widget/vim-surround.sh/vsurround { # vS + ble/widget/vi-command/operator vS +} +function ble/widget/vim-surround.sh/vgsurround { # vgS + [[ $_ble_decode_keymap == vi_xmap ]] && + ble/keymap:vi/xmap/add-eol-extension # 末尾拡張 + ble/widget/vi-command/operator vgS +} +_ble_lib_vim_surround_ys_repeat=() +function ble/lib/vim-surround.sh/ysurround.repeat/entry { + local -a _ble_keymap_vi_repeat _ble_keymap_vi_repeat_irepeat + ble/keymap:vi/repeat/record-normal + _ble_lib_vim_surround_ys_repeat=("${_ble_keymap_vi_repeat[@]}") +} +function ble/lib/vim-surround.sh/ysurround.repeat/record { + ble/keymap:vi/repeat/record-special && return 0 + local type=$1 ins=$2 + _ble_keymap_vi_repeat=("${_ble_lib_vim_surround_ys_repeat[@]}") + _ble_keymap_vi_repeat_irepeat=() + _ble_keymap_vi_repeat[10]=$type + _ble_keymap_vi_repeat[11]=$ins + case $type in + (vS|vgS) + _ble_keymap_vi_repeat[2]='ble/widget/vi-command/operator ysurround.repeat' + _ble_keymap_vi_repeat[4]= ;; + (yss|ySS) + _ble_keymap_vi_repeat[2]='ble/widget/vi_nmap/linewise-operator ysurround.repeat' + _ble_keymap_vi_repeat[4]= ;; + (*) + _ble_keymap_vi_repeat[4]=ysurround.repeat + esac +} +function ble/keymap:vi/operator:ysurround.repeat { + _ble_lib_vim_surround_ys_type=${_ble_keymap_vi_repeat[10]} + _ble_lib_vim_surround_ys_args=("$@") + [[ $3 == block ]] && _ble_lib_vim_surround_ys_ranges=("${sub_ranges[@]}") + local ins=${_ble_keymap_vi_repeat[11]} + ble/widget/vim-surround.sh/ysurround.core "$ins" +} +function ble/keymap:vi/operator:surround.record { :; } +function ble/keymap:vi/operator:surround { + local beg=$1 end=$2 context=$3 + local content=$surround_content ins=$surround_ins trims=$surround_trim + local ret + if [[ $trims ]]; then + ble/string#trim "$content"; content=$ret + fi + local opts=; [[ $surround_type == cS ]] && opts=linewise + if ! ble/lib/vim-surround.sh/surround "$content" "$ins" "$opts"; then + ble/widget/vi-command/bell + return 0 + fi + content=$ret + ble/widget/.replace-range "$beg" "$end" "$content" + return 0 +} +function ble/keymap:vi/operator:surround-extract-region { + surround_beg=$beg surround_end=$end + return 147 # 強制中断する為 +} +_ble_lib_vim_surround_cs=() +function ble/widget/vim-surround.sh/nmap/csurround.initialize { + _ble_lib_vim_surround_cs=("${@:1:3}") + return 0 +} +function ble/widget/vim-surround.sh/nmap/csurround.set-delimiter { + local type=${_ble_lib_vim_surround_cs[0]} + local arg=${_ble_lib_vim_surround_cs[1]} + local reg=${_ble_lib_vim_surround_cs[2]} + _ble_lib_vim_surround_cs[3]=$1 + local trim= + [[ $del == ' '?* ]] && trim=1 del=${del:1} + if [[ $del == a ]]; then + del='>' + elif [[ $del == r ]]; then + del=']' + elif [[ $del == T ]]; then + del='t' trim=1 + fi + local obj1= obj2= + case "$del" in + ([wWps]) obj1=i$del obj2=i$del ;; + ([\'\"\`]) obj1=i$del obj2=a$del arg=1 ;; + (['bB)}>]t']) obj1=i$del obj2=a$del ;; + (['({<[']) obj1=i$del obj2=a$del trim=1 ;; + ([a-zA-Z]) obj1=i$del obj2=a$del ;; + esac + local beg end + if [[ $obj1 && $obj2 ]]; then + local surround_beg=$_ble_edit_ind surround_end=$_ble_edit_ind + ble/keymap:vi/text-object.impl "$arg" surround-extract-region '' "$obj2" + beg=$surround_beg end=$surround_end + elif [[ $del == / ]]; then + local rex='(/\*([^/]|/[^*])*/?){1,'$arg'}$' + [[ ${_ble_edit_str::_ble_edit_ind+2} =~ $rex ]] || return 1 + beg=$((_ble_edit_ind+2-${#BASH_REMATCH})) + ble/string#index-of "${_ble_edit_str:beg+2}" '*/' || return 1 + end=$((beg+ret+4)) + elif [[ $del ]]; then + local ret + ble-edit/content/find-logical-bol; local bol=$ret + ble-edit/content/find-logical-eol; local eol=$ret + local line=${_ble_edit_str:bol:eol-bol} + local ind=$((_ble_edit_ind-bol)) + if ble/string#last-index-of "${line::ind}" "$del"; then + beg=$ret + elif local base=$((ind-(2*${#del}-1))); ((base>=0||(base=0))) + ble/string#index-of "${line:base:ind+${#del}-base}" "$del"; then + beg=$((base+ret)) + else + return 1 + fi + ble/string#index-of "${line:beg+${#del}}" "$del" || return 1 + end=$((beg+2*${#del}+ret)) + ((beg+=bol,end+=bol)) + fi + _ble_lib_vim_surround_cs[11]=$del + _ble_lib_vim_surround_cs[12]=$obj1 + _ble_lib_vim_surround_cs[13]=$obj2 + _ble_lib_vim_surround_cs[14]=$beg + _ble_lib_vim_surround_cs[15]=$end + _ble_lib_vim_surround_cs[16]=$arg + _ble_lib_vim_surround_cs[17]=$trim +} +function ble/widget/vim-surround.sh/nmap/csurround.replace { + local ins=$1 + local type=${_ble_lib_vim_surround_cs[0]} + local arg=${_ble_lib_vim_surround_cs[1]} + local reg=${_ble_lib_vim_surround_cs[2]} + local del=${_ble_lib_vim_surround_cs[3]} + local del2=${_ble_lib_vim_surround_cs[11]} + local obj1=${_ble_lib_vim_surround_cs[12]} + local obj2=${_ble_lib_vim_surround_cs[13]} + local beg=${_ble_lib_vim_surround_cs[14]} + local end=${_ble_lib_vim_surround_cs[15]} + local arg2=${_ble_lib_vim_surround_cs[16]} + local surround_ins=$ins + local surround_type=$type + local surround_trim=${_ble_lib_vim_surround_cs[17]} + if [[ $obj1 && $obj2 ]]; then + local ind=$_ble_edit_ind + local _ble_edit_kill_ring _ble_edit_kill_type + ble/keymap:vi/text-object.impl "$arg2" y '' "$obj1"; local ext=$? + _ble_edit_ind=$ind + ((ext!=0)) && return 1 + local surround_content=$_ble_edit_kill_ring + ble/keymap:vi/text-object.impl "$arg2" surround '' "$obj2" || return 1 + elif [[ $del2 == / ]]; then + local surround_content=${_ble_edit_str:beg+2:end-beg-4} + ble/keymap:vi/call-operator surround "$beg" "$end" char '' '' + _ble_edit_ind=$beg + elif [[ $del2 ]]; then + local surround_content=${_ble_edit_str:beg+${#del2}:end-beg-2*${#del2}} + ble/keymap:vi/call-operator surround "$beg" "$end" char '' '' + _ble_edit_ind=$beg + else + ble/widget/vi-command/bell + return 1 + fi + ble/widget/vim-surround.sh/nmap/csurround.record "$type" "$arg" "$reg" "$del" "$ins" + ble/keymap:vi/adjust-command-mode + return 0 +} +function ble/widget/vim-surround.sh/nmap/csurround.record { + [[ $_ble_keymap_vi_mark_suppress_edit ]] && return 0 + local type=$1 arg=$2 reg=$3 del=$4 ins=$5 + local WIDGET=ble/widget/vim-surround.sh/nmap/csurround.repeat ARG=$arg FLAG= REG=$reg + ble/keymap:vi/repeat/record + if [[ $_ble_decode_keymap == vi_imap ]]; then + _ble_keymap_vi_repeat_insert[10]=$type + _ble_keymap_vi_repeat_insert[11]=$del + _ble_keymap_vi_repeat_insert[12]=$ins + else + _ble_keymap_vi_repeat[10]=$type + _ble_keymap_vi_repeat[11]=$del + _ble_keymap_vi_repeat[12]=$ins + fi +} +function ble/widget/vim-surround.sh/nmap/csurround.repeat { + local ARG FLAG REG; ble/keymap:vi/get-arg 1 + local type=${_ble_keymap_vi_repeat[10]} + local del=${_ble_keymap_vi_repeat[11]} + local ins=${_ble_keymap_vi_repeat[12]} + ble/widget/vim-surround.sh/nmap/csurround.initialize "$type" "$ARG" "$REG" && + ble/widget/vim-surround.sh/nmap/csurround.set-delimiter "$del" && + ble/widget/vim-surround.sh/nmap/csurround.replace "$ins" && return 0 + ble/widget/vi-command/bell + return 1 +} +function ble/widget/vim-surround.sh/nmap/dsurround { + local ARG FLAG REG; ble/keymap:vi/get-arg 1 + ble/widget/vim-surround.sh/nmap/csurround.initialize ds "$ARG" "$REG" + ble/lib/vim-surround.sh/async-inputtarget ble/widget/vim-surround.sh/nmap/dsurround.hook +} +function ble/widget/vim-surround.sh/nmap/dsurround.hook { + local del=$1 + ble/widget/vim-surround.sh/nmap/csurround.set-delimiter "$del" && + ble/widget/vim-surround.sh/nmap/csurround.replace '' && return 0 + ble/widget/vi-command/bell + return 1 +} +function ble/highlight/layer:region/mark:vi_csurround/get-selection { + local beg=${_ble_lib_vim_surround_cs[14]} + local end=${_ble_lib_vim_surround_cs[15]} + selection=("$beg" "$end") +} +function ble/highlight/layer:region/mark:vi_csurround/get-face { + face=region_target +} +function ble/widget/vim-surround.sh/nmap/csurround { + ble/widget/vim-surround.sh/nmap/csurround.impl cs +} +function ble/widget/vim-surround.sh/nmap/cSurround { + ble/widget/vim-surround.sh/nmap/csurround.impl cS +} +function ble/widget/vim-surround.sh/nmap/csurround.impl { + local ARG FLAG REG; ble/keymap:vi/get-arg 1 + local type=$1 + ble/widget/vim-surround.sh/nmap/csurround.initialize "$type" "$ARG" "$REG" + ble/lib/vim-surround.sh/async-inputtarget ble/widget/vim-surround.sh/nmap/csurround.hook1 +} +function ble/widget/vim-surround.sh/nmap/csurround.hook1 { + local del=$1 + if [[ $del ]] && ble/widget/vim-surround.sh/nmap/csurround.set-delimiter "$del"; then + _ble_edit_mark_active=vi_csurround + ble/lib/vim-surround.sh/async-inputtarget-noarg ble/widget/vim-surround.sh/nmap/csurround.hook2 + return "$?" + fi + _ble_lib_vim_surround_cs=() + ble/widget/vi-command/bell + return 1 +} +function ble/widget/vim-surround.sh/nmap/csurround.hook2 { + local ins=$1 + if local rex='^ ?[<tT]$'; [[ $ins =~ $rex ]]; then + ble/lib/vim-surround.sh/async-read-tagname "ble/widget/vim-surround.sh/nmap/csurround.hook3 '$ins'" + else + ble/widget/vim-surround.sh/nmap/csurround.hook3 "$ins" + fi +} +function ble/widget/vim-surround.sh/nmap/csurround.hook3 { + local ins=$1 tagName=$2 + _ble_edit_mark_active= # clear mark:vi_csurround + ble/widget/vim-surround.sh/nmap/csurround.replace "$ins$tagName" && return 0 + ble/widget/vi-command/bell + return 1 +} +function ble/widget/vim-surround.sh/omap { + local ret n=${#KEYS[@]} + if ! ble/keymap:vi/k2c "${KEYS[n?n-1:0]}"; then + ble/widget/.bell + return 1 + fi + ble/util/c2s "$ret"; local s=$ret + local opfunc=${_ble_keymap_vi_opfunc%%:*}$s + local opflags=${_ble_keymap_vi_opfunc#*:} + case "$opfunc" in + (y[sS]) + local ARG FLAG REG; ble/keymap:vi/get-arg 1 + _ble_edit_arg=$ARG + _ble_keymap_vi_reg=$REG + ble/decode/keymap/pop + ble/widget/vi-command/operator "$opfunc:$opflags" ;; + (yss) + ble/widget/vi_nmap/linewise-operator "yss:$opflags" ;; + (yS[sS]) + ble/widget/vi_nmap/linewise-operator "ySS:$opflags" ;; + (ds) ble/widget/vim-surround.sh/nmap/dsurround ;; + (cs) ble/widget/vim-surround.sh/nmap/csurround ;; + (cS) ble/widget/vim-surround.sh/nmap/cSurround ;; + (*) ble/widget/.bell ;; + esac +} +ble-bind -m vi_xmap -f 'S' vim-surround.sh/vsurround +ble-bind -m vi_xmap -f 'g S' vim-surround.sh/vgsurround +if [[ $bleopt_vim_surround_omap_bind ]]; then + ble-bind -m vi_omap -f s 'vim-surround.sh/omap' + ble-bind -m vi_omap -f S 'vim-surround.sh/omap' +else + ble-bind -m vi_nmap -f 'y s' 'vi-command/operator ys' + ble-bind -m vi_nmap -f 'y s s' 'vim-surround.sh/ysurround-current-line' + ble-bind -m vi_nmap -f 'y S' 'vi-command/operator yS' + ble-bind -m vi_nmap -f 'y S s' 'vim-surround.sh/ySurround-current-line' + ble-bind -m vi_nmap -f 'y S S' 'vim-surround.sh/ySurround-current-line' + ble-bind -m vi_nmap -f 'd s' 'vim-surround.sh/nmap/dsurround' + ble-bind -m vi_nmap -f 'c s' 'vim-surround.sh/nmap/csurround' + ble-bind -m vi_nmap -f 'c S' 'vim-surround.sh/nmap/cSurround' +fi |