From d6242a7943efcc6de8e34aec36ede2fa51758ed8 Mon Sep 17 00:00:00 2001 From: Koichi Murase Date: Sun, 19 Dec 2021 09:52:06 +0900 Subject: [PATCH] complete, syntax (alias): exclude inactive aliases and fix the other quoting behavior --- docs/ChangeLog.md | 3 ++ lib/core-complete.sh | 68 ++++++++++++++++++++++++++++++++------------ lib/core-syntax.sh | 12 ++++++-- lib/test-util.sh | 22 +++++++------- note.txt | 35 +++++++++++++++++++++-- src/edit.sh | 4 +-- src/util.sh | 58 ++++++++++++++++++++++++++++++------- 7 files changed, 156 insertions(+), 46 deletions(-) diff --git a/docs/ChangeLog.md b/docs/ChangeLog.md index bda3abbb..39219de5 100644 --- a/docs/ChangeLog.md +++ b/docs/ChangeLog.md @@ -128,6 +128,9 @@ - syntax: revert 371a5a4 and generate empty completion source on syntax error `#D1609` e09fcab - syntax: strictly check variable names of `for`-statements `#D1692` d056547 - widget `self-insert`: untranslate control chars and insert the last character `#D1696` 5ff3021 +- complete (`source:command`): exclude inactive aliases `#D1715` 0000000 +- complete (`source:command`): not quote aliases and keywords `#D1715` 0000000 +- highlight (`wtype=CTX_CMDI`): check alias names before shell expansions `#D1715` 0000000 ## Fixes diff --git a/lib/core-complete.sh b/lib/core-complete.sh index a2e0cff0..97629da8 100644 --- a/lib/core-complete.sh +++ b/lib/core-complete.sh @@ -1276,7 +1276,9 @@ function ble/complete/action/quote-insert { fi local escape_flags=$quote_escape_flags - if [[ $quote_action == progcomp ]]; then + if [[ $quote_action == command ]]; then + [[ $DATA == *:noquote:* || $COMPS == "$COMPV" && ( $CAND == '[[' || $CAND == '!' ) ]] && return 0 + elif [[ $quote_action == progcomp ]]; then [[ $comp_opts == *:noquote:* ]] && return 0 # bash-completion には compopt -o nospace として、 @@ -1420,7 +1422,9 @@ function ble/complete/action/quote-insert.batch/awk { function quote_insert(cand) { # progcomp 特有 - if (quote_action == "progcomp") { + 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; } @@ -1766,7 +1770,7 @@ function ble/complete/action:command/get-desc { case $type in ($_ble_attr_CMD_ALIAS) local ret - ble/util/expand-alias "$CAND" + ble/alias#expand "$CAND" title=alias value=$ret ;; ($_ble_attr_CMD_FILE) local path; ble/util/assign path 'type -p -- "$CAND"' @@ -2298,10 +2302,15 @@ function ble/complete/source:command { ble/complete/source/test-limit ${#arr[@]} || return 1 - # keyword 判定用 - local rex_keyword= - [[ $COMPS != $COMPV ]] && - local rex_keyword='^(if|then|else|elif|fi|case|esac|for|select|while|until|do|done|function|time|[{}]|\[\[|coproc)$' + local action=command "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe + ble/complete/cand/yield.initialize "$action" + + # 無効 keyword, alias 判定用 + 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 @@ -2311,18 +2320,41 @@ function ble/complete/source:command { # 厳密一致のディレクトリ名が混入するので削除する。 [[ $cand != */ && -d $cand ]] && ! type "$cand" &>/dev/null && continue - # #D1691 keyword は quote されている場合には無効 - if [[ $rex_keyword && $cand =~ $rex_keyword ]]; then - local type; ble/util/type type "$cand" - ((${#type[@]}==1)) && continue + if [[ $is_quoted ]]; then + local disable_count= + # #D1691 keyword は quote されている場合には無効 + [[ $cand =~ $rex_keyword ]] && ((disable_count++)) + # #D1715 alias も quote されている場合には無効 + [[ $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 + # 'in' と ']]' は alias でない限り常にエラー + [[ $cand == ']]' || $cand == in ]] && + ! { [[ $expand_aliases ]] && ble/is-alias "$cand"; } && + continue + + if [[ ! $expand_aliases ]]; then + # #D1715 expand_aliases が無効でも compgen -c は alias を列挙してしまうので、 + # ここで alias は除外 (type は expand_aliases をちゃんと考慮してくれる)。 + ble/is-alias "$cand" && ! type "$cand" &>/dev/null && continue + fi + + # alias は quote されては困るので、quote される可能性のある文字を含んでい + # る場合は個別に :noquote: 指定で yield する [ Note: alias 内で許される特 + # 殊文字は !#%-~^[]{}+*:@,.?_ である。更にその中で escape/quote の対象と + # なり得る文字は、[*?]{,}!^~#: だけである。_.@+%- は quote されない ]。 + if ble/string#match "$cand" '[][*?{,}!^~#]' && ble/is-alias "$cand"; then + ble/complete/cand/yield "$action" "$cand" :noquote: + continue + fi fi + cands[icand++]=$cand done - ((icand)) || return 1 - - local "${_ble_complete_yield_varnames[@]/%/=}" # WA #D1570 safe - ble/complete/cand/yield.initialize command - ble/complete/cand/yield.batch command + ble/complete/cand/yield.batch "$action" } # source:file, source:dir @@ -3518,7 +3550,7 @@ function ble/complete/progcomp { ((_ble_bash<50000)) || shopt -q progcomp_alias || break local ret - ble/util/expand-alias "$cmd" + ble/alias#expand "$cmd" [[ $ret == "$cmd" ]] && break ble/complete/progcomp/.split-alias-words "$ret" if ((${#ret[@]}==0)); then @@ -4590,7 +4622,7 @@ function ble/complete/source:option { local alias_checked=' ' while local ret; ! ble/complete/mandb/load-cache "$cmd"; do alias_checked=$alias_checked$cmd' ' - ble/util/expand-alias "$cmd" || return 1 + ble/alias#expand "$cmd" || return 1 local words; ble/string#split-words ret "$ret"; words=("${ret[@]}") # 変数代入は読み飛ばし diff --git a/lib/core-syntax.sh b/lib/core-syntax.sh index 7d8ba880..93bee6b5 100644 --- a/lib/core-syntax.sh +++ b/lib/core-syntax.sh @@ -3488,7 +3488,7 @@ function ble/syntax:bash/ctx-command/check-word-end { if ((ctx==CTX_CMDI)); then local ret - ble/util/expand-alias "$word"; local word_expanded=$ret + ble/alias#expand "$word"; local word_expanded=$ret # キーワードの処理 if ((wt!=CTX_CMDXV)); then # Note: 変数代入の直後はキーワードは処理しない @@ -6836,6 +6836,14 @@ function ble/progcolor/highlight-filename/.single.wattr { local p0=${1%%:*} p1=${1#*:} local wtxt=${text:p0:p1-p0} + # alias はシェル展開等を行う前に判定するべき + if ((wtype==CTX_CMDI)) && ble/alias#active "$wtxt"; then + # Note: [*?] 等の文字が含まれている alias 名の場合 failglob するかもしれ + # ないが、実際は展開されるので問題ない。 + ble/progcolor/wattr#setattr "$p0" "$ATTR_CMD_ALIAS" + return 0 + fi + local path_opts=after-sep:$highlight_eval_opts # チルダ展開の文脈でない時には抑制 [[ $wtxt == '~'* ]] && ((_ble_syntax_attr[p0]!=ATTR_TILDE)) && path_opts=$path_opts:notilde @@ -7042,7 +7050,7 @@ function ble/progcolor { checked="$checked$cmd " local ret - ble/util/expand-alias "$cmd" + ble/alias#expand "$cmd" ble/string#split-words ret "$ret" [[ $checked == *" $ret "* ]] && break cmd=$ret diff --git a/lib/test-util.sh b/lib/test-util.sh index e76a8197..d1398027 100644 --- a/lib/test-util.sh +++ b/lib/test-util.sh @@ -1353,25 +1353,25 @@ function is-global() (readonly "$1"; ! local "$1" 2>/dev/null) ble/test 'ble/util/type ret ble/fun1#meth' ret= ) -# ble/util/expand-alias +# ble/alias#expand ( shopt -s expand_aliases # Note: 複数段階の展開は実行しない alias aaa1='aaa2 world' - ble/test 'ble/util/expand-alias aaa1' ret='aaa2 world' + ble/test 'ble/alias#expand aaa1' ret='aaa2 world' alias aaa2='aaa3 hello' - ble/test 'ble/util/expand-alias aaa2' ret='aaa3 hello' - ble/test 'ble/util/expand-alias aaa1' ret='aaa2 world' + ble/test 'ble/alias#expand aaa2' ret='aaa3 hello' + ble/test 'ble/alias#expand aaa1' ret='aaa2 world' alias aaa3='aaa4' - ble/test 'ble/util/expand-alias aaa3' ret='aaa4' - ble/test 'ble/util/expand-alias aaa2' ret='aaa3 hello' - ble/test 'ble/util/expand-alias aaa1' ret='aaa2 world' + 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/util/expand-alias aaa4' ret='echo' - ble/test 'ble/util/expand-alias aaa3' ret='aaa4' - ble/test 'ble/util/expand-alias aaa2' ret='aaa3 hello' - ble/test 'ble/util/expand-alias aaa1' ret='aaa2 world' + 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' ) # ble/util/is-stdin-ready diff --git a/note.txt b/note.txt index c0c07577..8277bf74 100644 --- a/note.txt +++ b/note.txt @@ -1635,11 +1635,17 @@ bash_tips 2021-12-18 - * complete (source:command): quote していても alais が候補として生成されている - * bleopt menu_align_{min,max} これは別項目で議論する。 + * deprecated functions の枠組みを整える。 + + 散発的に deprecate して行くと毎回設定を変更しなければならず面倒なので、 + version を指定して特定の version 以降になった時に限り初回だけ警告を表示する + 様にするのが良い。 + + ((_ble_version>=500)) && ..... と言った具合。 + * complete: FIGNORE と -o filenames どうやら元の bash では -o filenames が指定された時にのみ FIGNORE が使われる @@ -5692,6 +5698,31 @@ bash_tips 2021-12-18 + * complete (source:command): quote していても alias が候補として生成されている [#D1715] + その為に、menu の中でエラー着色されている。 + + うーん。特に自分で alias を生成している訳ではなくて compgen -c -- s 等の時 + 点で alias が生成される様だ。一方で、 compgen -c -- "'s'" 等とすると、何も + 生成されなくなってしまうので alias を除外した生成にする事は難しそうである。 + + 更に compgen -c は expand_aliases が off になっていても alias を列挙する様だ。 + + 一方で、for 等の keyword はどの様に判定しているのだったか。うーん。 + source:command で filter している様だ。同じ箇所で alias のチェックもする事 + にした。 + + x fixed: 実装してみたら全て赤くなっている→ これは今回の編集ではなくて前回 + の commit の時点で既に駄目になっている。#D1714 で修正した。 + + x fixed: alias は noquote を付加する必要があるのでは? → 修正した。その他に + も ! や [[ 等は quote しない様にする必要がある。 + + x fixed: alias が *? 等の文字を含んでいる場合コマンド着色でエラーになってし + まう。修正した。 + + と思ったが、考えてみれば、そもそも alias 名に一致している場合には展開を試 + みる前に alias に確定させるべきなのではないか。 + * menu-complete で 30s かかるという話 (2/2) yield quote-insert 高速化の試み [#D1714] https://github.com/banoris/dotfiles/issues/11 diff --git a/src/edit.sh b/src/edit.sh index f0ea15db..f56b0e7b 100644 --- a/src/edit.sh +++ b/src/edit.sh @@ -5994,7 +5994,7 @@ function ble/widget/alias-expand-line.proc { ble/widget/alias-expand-line.proc elif [[ $wtype && ! ${wtype//[0-9]} ]] && ((wtype==_ble_ctx_CMDI)); then local word=${_ble_edit_str:wbegin:wlen} - local ret; ble/util/expand-alias "$word" + local ret; ble/alias#expand "$word" [[ $word == "$ret" ]] && return 0 changed=1 ble/widget/.replace-range "$wbegin" $((wbegin+wlen)) "$ret" @@ -6061,7 +6061,7 @@ function ble/widget/shell-expand-line.expand-word { # エイリアス展開 if ((wtype==_ble_ctx_CMDI)); then - ble/util/expand-alias "$word" + ble/alias#expand "$word" [[ $word != $ret ]] && return 0 fi diff --git a/src/util.sh b/src/util.sh index ad533cf5..0ce9ff96 100644 --- a/src/util.sh +++ b/src/util.sh @@ -2910,17 +2910,53 @@ function ble/util/type { ble/util/assign-array "$1" 'builtin type -a -t -- "$3" 2>/dev/null' "$2"; local ext=$? return "$ext" } -## @fn ble/util/expand-alias word -## @var[out] ret -## @exit -## エイリアス展開が実際に行われた時に成功します。 -function ble/util/expand-alias { - ret=$1 - local type; ble/util/type type "$ret" - [[ $type != alias ]] && return 1 - local data; ble/util/assign data 'LC_ALL=C alias "$ret"' &>/dev/null - [[ $data == 'alias '*=* ]] && builtin eval "ret=${data#alias *=}" -} + +if ((_ble_bash>=40000)); then + function ble/is-alias { + [[ ${BASH_ALIASES[$1]+set} ]] + } + function ble/alias#active { + shopt -q expand_aliases && + [[ ${BASH_ALIASES[$1]+set} ]] + } + ## @fn ble/alias#expand word + ## @var[out] ret + ## @exit + ## エイリアス展開が実際に行われた時に成功します。 + function ble/alias#expand { + ret=$1 + shopt -q expand_aliases && + ret=${BASH_ALIASES[$ret]-$ret} + } + function ble/alias/list { + ret=("${!BASH_ALIASES[@]}") + } +else + function ble/is-alias { + [[ $1 != *=* ]] && alias "$1" >/dev/null + } + function ble/alias#active { + shopt -q expand_aliases && + [[ $1 != *=* ]] && alias "$1" >/dev/null + } + function ble/alias#expand { + ret=$1 + local type; ble/util/type type "$ret" + [[ $type != alias ]] && return 1 + local data; ble/util/assign data 'LC_ALL=C alias "$ret"' &>/dev/null + [[ $data == 'alias '*=* ]] && builtin eval "ret=${data#alias *=}" + } + function ble/alias/list { + ret=() + local data iret=0 + ble/util/assign-array data 'alias -p' + for data in "${data[@]}"; do + [[ $data == 'alias '*=* ]] && + data=${data%%=*} && + builtin eval "ret[iret++]=${data#alias }" + done + } +fi if ((_ble_bash>=40000)); then # #D1341 対策 変数代入形式だと組み込みコマンドにロケールが適用されない。