diff --git a/docs/ChangeLog.md b/docs/ChangeLog.md index c550fa0f..d6019695 100644 --- a/docs/ChangeLog.md +++ b/docs/ChangeLog.md @@ -115,7 +115,8 @@ - menu-complete: add `bleopt complete_menu_complete_opts` (requested by DUOLabs333) `#D1911` 6a21ebb - edit (`magic-space`): support `bleopt edit_magic_expand=...:alias` (requested by telometto) `#D1912` 63da2ac - auto-complete: cancel auto-complete for `magic-space` `#D1913` 01b4f67 -- complete: support ambiguous completion for command paths `#D1922` xxxxxxx +- complete: support ambiguous completion for command paths `#D1922` 8a716ad +- complete: preserve original path segments as long as possible `#D1923` `#D1924` xxxxxxx ## Changes diff --git a/lib/core-complete.sh b/lib/core-complete.sh index 9ea1fb3a..4b8eafdc 100644 --- a/lib/core-complete.sh +++ b/lib/core-complete.sh @@ -1267,16 +1267,27 @@ function ble/complete/action/quote-insert.initialize { esac # 遡って書き換える時に comps_fixed には注意する。 - quote_fixed_comps= - quote_fixed_compv= - quote_fixed_comps_len= - quote_fixed_compv_len= + 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 + + # 遡って書き換える時に '/' 区切りでできるだけ元の展開を保持する。 + # comps_fixed[1] 以降に '/' 区切りで展開した結果を短い順に格納する。 + local i v + for ((i=1;i<${#comps_fixed[@]};i++)); do + v=${comps_fixed[i]#*:} + quote_fixed_compv[i]=$v + quote_fixed_compv_len[i]=${#v} + quote_fixed_comps_len[i]=${comps_fixed[i]%%:*} + quote_fixed_comps[i]=${COMPS::quote_fixed_comps_len[i]} + done } function ble/complete/action/quote-insert { @@ -1301,6 +1312,7 @@ function ble/complete/action/quote-insert { 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 @@ -1310,13 +1322,22 @@ function ble/complete/action/quote-insert { [[ $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 + return 0 fi + + # 遡って書き換わる場合には単語内のできるだけ長い部分パスを保持する。 + local i=${#quote_fixed_comps[@]} + while ((--i>=0)); do + if [[ ${quote_fixed_comps[i]} && $CAND == "${quote_fixed_compv[i]}"* ]]; then + local ret; ble/complete/string#escape-for-completion-context "${CAND:quote_fixed_compv_len[i]}" "$escape_flags" + INSERT=${quote_fixed_comps[i]}$quote_trav_prefix$ret + return 0 + fi + done + + # 既存の物に一致しない場合、完全に書き換える。 + local ret; ble/complete/string#escape-for-completion-context "$CAND" "$escape_flags" + INSERT=$quote_trav_prefix$ret } function ble/complete/action/quote-insert.batch/awk { @@ -1330,13 +1351,19 @@ function ble/complete/action/quote-insert.batch/awk { 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 + + local -x quote_fixed_count=${#quote_fixed_comps[@]} + local i + for ((i=0;i= 0; ) { + if (quote_fixed_comps_len[i] && substr(cand, 1, quote_fixed_compv_len[i]) == quote_fixed_compv[i]) { + ins = substr(cand, quote_fixed_compv_len[i] + 1); + return quote_fixed_comps[i] quote_trav_prefix escape_for_completion_context(ins); + } + } + + return quote_trav_prefix escape_for_completion_context(cand); } { @@ -5529,7 +5564,7 @@ function ble/complete/candidates/.pick-nearest-sources { COMPS=${comp_text:COMP1:COMP2-COMP1} comps_flags= - comps_fixed= + comps_fixed=('') if [[ ! $COMPS ]]; then comps_flags=${comps_flags}v COMPV= @@ -5553,6 +5588,14 @@ function ble/complete/candidates/.pick-nearest-sources { comps_fixed=${simple_ibrace%:*}:$ret comps_flags=${comps_flags}x fi + + local path spec i s + ble/syntax:bash/simple-word/evaluate-path-spec "$reconstructed" '' noglob:fixlen="${simple_ibrace#*:}" + for ((i=0;i<${#spec[@]};i++)); do + s=${spec[i]} + [[ $s == "$comps_fixed" || $s == "$reconstructed" ]] && continue + ble/array#push comps_fixed "${#s}:${path[i]}" + done else # Note: failglob により simple-word/eval が失敗した時にここに来る。 COMPV= diff --git a/lib/core-syntax.sh b/lib/core-syntax.sh index b01be636..fff9c301 100644 --- a/lib/core-syntax.sh +++ b/lib/core-syntax.sh @@ -1571,8 +1571,15 @@ function ble/syntax:bash/simple-word/.get-rex_element { ## timeout=* ## timeout-carry ## cached +## これらは simple-word/eval に対するオプションです。 +## ## notilde +## 評価時にチルダ展開を抑制します。 ## after-sep +## 分割位置を分割子の前ではなく後に変更します。 +## fixlen=LEN +## 分割の対象とならない固定接頭辞の長さを指定します。 +## ## @arr[out] spec ## @arr[out] path ## @arr[out] ret @@ -1595,6 +1602,8 @@ function ble/syntax:bash/simple-word/evaluate-path-spec { # read options local eval_opts=$opts notilde= [[ :$opts: == *:notilde:* ]] && notilde=\'\' # チルダ展開の抑制 + local fixlen + ble/opts#extract-last-optarg "$opts" fixlen 0 # compose regular expressions local rex_element; ble/syntax:bash/simple-word/.get-rex_element "$sep" @@ -1602,7 +1611,7 @@ function ble/syntax:bash/simple-word/evaluate-path-spec { [[ :$opts: == *:after-sep:* ]] && local rex='^'$rex_element'['$sep']?|^['$sep']' - local tail=$word s= p= ext=0 + local tail=${word:fixlen} s=${word::fixlen} p= ext=0 while [[ $tail =~ $rex ]]; do local rematch=$BASH_REMATCH s=$s$rematch diff --git a/note.txt b/note.txt index c5c7fed1..5895c49c 100644 --- a/note.txt +++ b/note.txt @@ -1861,25 +1861,6 @@ bash_tips - leakvars - keymap の移動 (これは別 commit にする?) -2023-01-24 - - * complete: パス名の曖昧補間でできるだけ各種展開を保持したい - - 現在の実装では quote-insert で生成候補が COMPV に文字列を追加した物の場合に - は COMPV の部分については COMPS で置き換える様になっている。しかし、遡った - 置換がある場合には問答無用で全体が展開されてしまうので、曖昧補間が起こった - 時には必ず全体が展開されてしまう。 - - COMPS を unquoted / 毎に切って、eval して対応する部分 compv を生成して、最 - 長一致するものについて部分 comps で置き換える。unquote / 毎に切るのは個別の - quote-insert でやっていたら大変なので、事前に処理しておく事にする。 - - quote-insert.batch で awk で処理する場合にどうするのかについては微妙。awk - の内部で unquote / 毎に切るのを実装するか或いは外で切ったものを何とかして - awk に渡すかする。外で定義したものを渡す方が見通しが良いと思われる。 - - ToDo 2022-02-03 に関連項目がある。 - 2022-12-09 * edit,complete: alias expansion で alias sudo='sudo ' 等による引数の展開に対応? @@ -2410,22 +2391,6 @@ bash_tips うーん。load time で time stamp を書き換える様にすれば良いのだろうか。 - * complete: 補完している時に勝手に変数の中身が展開されてしまう事がある。展開 - する条件をより制限する事はできないか。或いは、展開せずに置換できるパターン - を増やす。 - - 最たる場合が echo $_ble_base_cache/mandb[TAB] である。曖昧一致によって遡っ - て置換が起こるが、それによって変数展開の中身まで展開されてしまう。少なくと - も / で区切ってできるだけ展開せずに一致する様にできないだろうか。 - - ? 曖昧一致に於いて変数展開から得られた文字列は塊で取り扱う? - - というかよく考えたら変数の中身に対してまで曖昧一致で一致させるのは変な気 - がする。曖昧一致は元の原始的な構成要素に対しては塊で一致する様にするべき - なのではないか。と思ったが 'aaa' の中身の様にユーザーが手で入力した内容に - ついてはやはり曖昧一致であって欲しい。という事を考えると曖昧一致で塊とす - るとしてもその対象は変数展開だけに限られてくるのではないか。 - 2022-01-23 * コマンドのログ機能を作成する。 @@ -6691,6 +6656,70 @@ bash_tips 2023-01-24 + * [自然解消] 2022-02-03 complete: 補完している時に勝手に変数の中身が展開されてしまう事がある [#D1924] + + 展開する条件をより制限する事はできないか。或いは、展開せずに置換できるパター + ンを増やす。 + + 最たる場合が echo $_ble_base_cache/mandb[TAB] である。曖昧一致によって遡っ + て置換が起こるが、それによって変数展開の中身まで展開されてしまう。少なくと + も / で区切ってできるだけ展開せずに一致する様にできないだろうか。 + + ? 曖昧一致に於いて変数展開から得られた文字列は塊で取り扱う? + + というかよく考えたら変数の中身に対してまで曖昧一致で一致させるのは変な気 + がする。曖昧一致は元の原始的な構成要素に対しては塊で一致する様にするべき + なのではないか。と思ったが 'aaa' の中身の様にユーザーが手で入力した内容に + ついてはやはり曖昧一致であって欲しい。という事を考えると曖昧一致で塊とす + るとしてもその対象は変数展開だけに限られてくるのではないか。 + + 2023-01-24 #D1923 で曖昧一致によって遡って書き換わって展開される場合につい + て対応した。勝手に変数の中身が展開されるパターンがこれだけなのかは分からな + いが、取り敢えずは解決した事にする。暫く使って勝手に展開されてしまう他のケー + スに気づいたらその時に新しく項目を立てて対応する事にする。 + + * complete: パス名の曖昧補間でできるだけ各種展開を保持したい [#D1923] + + 現在の実装では quote-insert で生成候補が COMPV に文字列を追加した物の場合に + は COMPV の部分については COMPS で置き換える様になっている。しかし、遡った + 置換がある場合には問答無用で全体が展開されてしまうので、曖昧補間が起こった + 時には必ず全体が展開されてしまう。 + + COMPS を unquoted / 毎に切って、eval して対応する部分 compv を生成して、最 + 長一致するものについて部分 comps で置き換える。unquote / 毎に切るのは個別の + quote-insert でやっていたら大変なので、事前に処理しておく事にする。 + + quote-insert.batch で awk で処理する場合にどうするのかについては微妙。awk + の内部で unquote / 毎に切るのを実装するか或いは外で切ったものを何とかして + awk に渡すかする。外で定義したものを渡す方が見通しが良いと思われる。 + + ToDo 2022-02-03 に関連項目がある → #D1924 + + unquoted / で区切るのは既存の + ble/syntax:bash/simple-word/evaluate-path-spec をそのまま使えば良い。 + + * reject: あらゆる単語について判定を行うと大変なので CAND が既存のファイル + 名に一致する時にだけチェックをおこなう? 未だ存在しないファイル名を候補と + して生成する可能性はあるだろうか。例えば Makefile target 等。うー + ん。-o$HOME/ 等の様に short option の optarg として指定している場合等も考 + えたら例え存在していなかったとしても一致するかのチェックはするべきの気が + する。 + + うーん。fixed part との兼ね合いがどうなるのか分からない。取り敢えず + evaluate-path-spec は noglob で呼び出す事にしてチルダ展開・パラメータ展開等 + 文脈に依存しない物のみを実行する事にする (コマンド置換、算術展開などは元よ + り simple-word ではないので対象ではない)。 + + ? quote-insert.initialize で実行するべきか或いは COMPV を評価する時点で + evaluate-path-spec で展開しておくべきか → COMPV を評価する時点で同時に評 + 価してしまうべきの気がしてきた。 + + 結局 fixed part を拡張する形で実装する事にした。既存の変数である + comps_fixed 及び quote_fixed_comp{s,v}{,_len} 等を配列に拡張して第1要素以降 + に部分パスの展開前・展開後を格納する事にする。 + + 実装した。取り敢えずは動いている気がする。 + * 2023-01-02 complete: コマンド名(パス名)の曖昧補間・部分一致など [#D1922] 現在の実装だと PATH に見つかっているコマンドについては曖昧補間が有効である