diff --git a/lib/core-complete.sh b/lib/core-complete.sh index 165b7582..089b8f95 100644 --- a/lib/core-complete.sh +++ b/lib/core-complete.sh @@ -206,16 +206,23 @@ function ble/complete/action/util/quote-insert { [[ $comps_flags == *B* && $COMPS == *'\' && $ins == '\'* ]] && ins=${ins:1} INSERT=$COMPS$ins - elif [[ $comps_fixed && $CAND == "${comps_fixed#*:}"* ]]; then - local comps_fixed_part=${COMPS::${comps_fixed%%:*}} - local compv_fixed_part=${comps_fixed#*:} - local ins=${CAND:${#compv_fixed_part}} - local ret; ble/string#escape-for-bash-specialchars-in-brace "$ins" - INSERT=$comps_fixed_part$ret - else - local ret - ble/string#escape-for-bash-specialchars "$CAND"; INSERT=$ret + local ins=$CAND comps_fixed_part= compv_fixed_part= + if [[ $comps_fixed && $CAND == "${comps_fixed#*:}"* ]]; then + comps_fixed_part=${COMPS::${comps_fixed%%:*}} + compv_fixed_part=${comps_fixed#*:} + ins=${CAND:${#compv_fixed_part}} + fi + + local ret; ble/complete/string#escape-for-completion-context "$ins"; ins=$ret + case $comps_flags in + (*S*) ins=\'$ins ;; + (*E*) ins=\$\'$ins ;; + (*D*) ins=\"$ins ;; + (*I*) ins=\$\"$ins ;; + esac + + INSERT=$comps_fixed_part$ins fi } @@ -453,6 +460,39 @@ function ble/complete/action:variable/init-menu-item { #============================================================================== # source +## 関数 ble/complete/source/reduce-compv-for-ambiguous-match +## 曖昧補完の為に擬似的な COMPV と COMPS を生成・設定します。 +## @var[in,out] COMPS COMPV +function ble/complete/source/reduce-compv-for-ambiguous-match { + [[ :$comp_type: == *:[amA]:* ]] || 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/cand/yield ACTION CAND DATA ## @param[in] ACTION ## @param[in] CAND @@ -514,13 +554,14 @@ function ble/complete/cand/unpack { ## # source:wordlist - +# +# -r 指定された単語をエスケープせずにそのまま挿入する +# -W 補完完了時に空白を挿入しない +# function ble/complete/source:wordlist { [[ $comps_flags == *v* ]] || return 1 - case :$comp_type: in - (*:a:*) local COMPS=${COMPS::1} COMPV=${COMPV::1} ;; - (*:[mA]:*) local COMPS= COMPV= ;; - esac + local COMPS=$COMPS COMPV=$COMPV + ble/complete/source/reduce-compv-for-ambiguous-match [[ $COMPV =~ ^.+/ ]] && COMP_PREFIX=${BASH_REMATCH[0]} # process options @@ -613,10 +654,8 @@ function ble/complete/source:command/.contract-by-slashes { } function ble/complete/source:command/gen.1 { - case :$comp_type: in - (*:a:*) local COMPS=${COMPS::1} COMPV=${COMPV::1} ;; - (*:[mA]:*) local COMPS= COMPV= ;; - esac + local COMPS=$COMPS COMPV=$COMPV + ble/complete/source/reduce-compv-for-ambiguous-match # Note: cygwin では cyg,x86,i68 等で始まる場合にとても遅い。 # 他の環境でも空の補完を実行すると遅くなる可能性がある。 @@ -748,7 +787,16 @@ function ble/complete/util/eval-pathname-expansion { fi fi - IFS= GLOBIGNORE= eval 'ret=(); ret=($pattern)' 2>/dev/null + 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 + + IFS= GLOBIGNORE= builtin eval "ret=(); ret=($pattern)" 2>/dev/null ble/util/invoke-hook dtor } @@ -772,10 +820,10 @@ function ble/complete/source:file/.construct-ambiguous-pathname-pattern { for name in "${names[@]}"; do ((i++)) && pattern=$pattern/ if [[ $name ]]; then - ble/string#escape-for-bash-glob "${name::fixlen}" + ble/string#quote-word "${name::fixlen}" pattern=$pattern$ret* for ((j=fixlen;j<${#name};j++)); do - ble/string#escape-for-bash-glob "${name:j:1}" + ble/string#quote-word "${name:j:1}" pattern=$pattern$ret* done fi @@ -793,7 +841,7 @@ function ble/complete/source:file/.construct-pathname-pattern { elif [[ :$comp_type: == *:[mA]:* ]]; then ble/complete/source:file/.construct-ambiguous-pathname-pattern "$path" 0; local pattern=$ret else - ble/string#escape-for-bash-glob "$path"; local pattern=$ret* + ble/string#quote-word "$path"; local pattern=$ret* fi ret=$pattern } @@ -1221,8 +1269,9 @@ function ble/complete/source:argument/.progcomp { # もし 124 だった場合には is_default_completion に retry を設定する。 if [[ $is_default_completion == retry && ! $_ble_complete_retry_guard ]]; then local _ble_complete_retry_guard=1 - ble/complete/source:argument/.progcomp "$@" - return + ble/path#remove opts default + ble/complete/source:argument/.progcomp "$opts" + return "$?" fi [[ $compgen ]] || return 1 @@ -1301,10 +1350,11 @@ function ble/complete/source:argument/.progcomp { ## @var[in] (variables set by ble/syntax/parse) ## function ble/complete/source:argument/.generate-user-defined-completion { - case :$comp_type: in - (*:a:*) local COMPS=${COMPS::1} COMPV=${COMPV::1} COMP2=$((COMP1+1)) ;; - (*:[mA]:*) local COMPS= COMPV= COMP2=$COMP1 ;; - esac + shopt -q progcomp || return 1 + + local COMPS=$COMPS COMPV=$COMPV + ble/complete/source/reduce-compv-for-ambiguous-match + [[ :$comp_type: == *:[amA]:* ]] && local COMP2=$COMP1 local comp_words comp_line comp_point comp_cword ble/syntax:bash/extract-command "$COMP2" || return 1 @@ -1392,10 +1442,8 @@ function ble/complete/source:argument { function ble/complete/source/compgen { [[ $comps_flags == *v* ]] || return 1 - case :$comp_type: in - (*:a:*) local COMPS=${COMPS::1} COMPV=${COMPV::1} ;; - (*:[mA]:*) local COMPS= COMPV= ;; - esac + local COMPS=$COMPS COMPV=$COMPV + ble/complete/source/reduce-compv-for-ambiguous-match local compgen_action=$1 local action=$2 diff --git a/lib/core-syntax.sh b/lib/core-syntax.sh index 76f6f522..9de2f059 100644 --- a/lib/core-syntax.sh +++ b/lib/core-syntax.sh @@ -158,6 +158,17 @@ _ble_syntax_TREE_WIDTH=5 # ble/syntax/tree-enumerate-children proc # ble/syntax/tree-enumerate-in-range beg end proc +function ble/syntax/tree-enumerate/.add-root-element { + local wtype=$1 wlen=$2 tclen=$3 tplen=$4 + + # Note: wtype は単語に格納される時に EndWtype テーブルで変換される。 + # ble/syntax:bash/ctx-command/check-word-end の実装を参照の事。 + [[ ! ${wtype//[0-9]} && ${_ble_syntax_bash_command_EndWtype[wtype]} ]] && + wtype=${_ble_syntax_bash_command_EndWtype[wtype]} + + root="$wtype $wlen $tclen $tplen -- $root" +} + ## 関数 ble/syntax/tree-enumerate/.initialize ## ## @var[in] iN @@ -194,7 +205,7 @@ function ble/syntax/tree-enumerate/.initialize { while if ((wlen>=0)); then - root="$wtype $wlen $tclen $tplen -- $root" + ble/syntax/tree-enumerate/.add-root-element "$wtype" "$wlen" "$tclen" "$tplen" tclen=0 fi ((inest>=0)) @@ -207,7 +218,7 @@ function ble/syntax/tree-enumerate/.initialize { tplen=${nest[4]} ((tplen>=0&&(tplen+=olen))) - root="${nest[7]} $olen $tclen $tplen -- $root" + 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), diff --git a/src/util.sh b/src/util.sh index b1afe661..c7ca0ca6 100644 --- a/src/util.sh +++ b/src/util.sh @@ -694,6 +694,30 @@ function ble/string#escape-for-bash-specialchars-in-brace { fi } +function ble/string#quote-word { + ret=$1 + + local opts=$2 sgrq= sgr0= + if [[ $opts ]]; then + local rex=':sgrq=([^:]*):' + [[ :$opts: =~ $rex ]] && + sgrq=${BASH_REMATCH[1]} sgr0=$_ble_term_sgr0 + rex=':sgr0=([^:]*):' + [[ :$opts: =~ $rex ]] && + sgr0=${BASH_REMATCH[1]} + fi + + local chars=$_ble_term_IFS'"`$\<>()|&;*?[]!^=:{,}#~' q=\' + if [[ $ret == *["$chars"]* ]]; then + local Q="'$sgr0\'$sgrq'" + ret=$sgrq$q${ret//$q/$Q}$q$sgr0 + ret=${ret#$q$q} ret=${ret%$q$q} + elif [[ $ret == *["$q"]* ]]; then + local Q="\'" + ret=${ret//$q/$Q} + fi +} + ## 関数 ble/string#create-unicode-progress-bar value max width ## @var[out] ret function ble/string#create-unicode-progress-bar { @@ -1152,6 +1176,15 @@ else } fi +## 関数 ble/util/is-cygwin-slow-glob word +## Cygwin では // で始まるパスの展開は遅い (#D1168) のでその判定を行う。 +function ble/util/is-cygwin-slow-glob { + # Note: core-complete.sh ではエスケープを行うので + # "'//...'" 等の様な文字列が "$1" に渡される。 + [[ ( $OSTYPE == cygwin || $OSTYPE == msys ) && ${1#\'} == //* && ! -o noglob ]] && + ble/util/has-glob-pattern "$1" +} + ## 関数 ble/util/eval-pathname-expansion pattern ## @var[out] ret function ble/util/eval-pathname-expansion {