diff --git a/contrib b/contrib index 120564bb..8e63bf61 160000 --- a/contrib +++ b/contrib @@ -1 +1 @@ -Subproject commit 120564bb2d94d40f1f483a3a852f2d206a0d23a9 +Subproject commit 8e63bf61b87e41df2a0f75de9d7bb635ab59c7cb diff --git a/lib/core-complete.sh b/lib/core-complete.sh index ebc521c8..76b2c0c8 100644 --- a/lib/core-complete.sh +++ b/lib/core-complete.sh @@ -5925,16 +5925,16 @@ function ble/complete/menu-complete.class/render-item { # 基本色の初期化 (Note: 高速化の為、直接 _ble_color_g2sgr を参照する) local sgrN0= sgrN1= sgrB0= sgrB1= - [[ :$opts: == *:selected:* ]] && ((g0|=_ble_color_gflags_Revert)) + [[ :$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=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=(g0|_ble_color_gflags_Bold)^_ble_color_gflags_Revert]} [[ $ret ]] || ble/color/g2sgr "$g"; sgrB1=$ret fi diff --git a/note.txt b/note.txt index 05eb8c6a..687a476a 100644 --- a/note.txt +++ b/note.txt @@ -1809,6 +1809,22 @@ bash_tips ToDo ------------------------------------------------------------------------------- +2022-03-19 + + * BUG bash-5.2 で \q{...} が動かなくなっている + + * 編集文字列に含まれる制御文字の反転表示の可能性 + + 現在は見た目には区別がつかない。プロンプトシーケンス \w, \W, etc に含まれる + 制御文字については反転の toggle で対処している。 + + 一方で、現在の実装だと単純に編集文字列に含まれる制御文字の反転状態を変更す + る事はできない。着色に関係なく制御文字の表現を決めている、つまり地の反転状 + 態に関係ない escape sequence を決める必要があるが、地の反転状態が分からなけ + れば制御文字が終わった位置で正しく反転状態を復元することができなくなる。 + + これについてはまた今後必要性を感じた時に実装すれば良い気がする。 + 2022-03-03 * 起動時の fork について @@ -6177,6 +6193,99 @@ bash_tips Done (実装ログ) ------------------------------------------------------------------------------- +2022-03-19 + + * menu-complete: 補完候補に含まれる制御文字の反転は xor で行う [#D1802] + + prompt seq \w, \W, \s で制御文字の反転を toggle する様にしたが、補完候補の + 表示でも同様に toggle した方が良い気がする。#D1798, #D1801 のテストの最中に + 実際に制御文字を含むディレクトリを作成して補完を実行した時にやはり気になっ + た。当初は #D1801 の一部として対応したが別項目に分けた方が良い様に感じるの + で分ける事にした。 + + * done: menu-complete: 特殊文字を含む候補の反転と選択時の反転が重なって見に + くい。反転は重ね書きではなくて toggle にするべきなのではないか。 + + 新しい \e[9807m で対応できるかと思って実装を確認したが trace は使っていな + くて直接画面に出力するのに使うシーケンスを sgr を直接指定することで構築し + ていたので使えなかった。その代わりに反転に使う sgr などをそもそもその場で + g|_ble_color_Revert 等として構築していたのでその | を ^ に置き換える事で + 簡単に対応する事ができた。 + + 一方で編集文字列に含まれる制御文字についても気になったがそもそも反転してい + ないので関係ないのであった。 + + * ok: 更に編集文字列本体についても同様に toggle するべきなのではないか? と + 思ったがそもそも現在の実装だと編集文字列に含まれる制御文字は特に反転など + していないので関係ないのであった。 + + 今から新しく対応しようにも現状の実装だと反転の toggle を実装するのは簡単 + ではない様なので取り敢えずは対応しない事にする。もし今後必要性を感じた時 + に改めて対応する事にすれば良い気がする。一応項目として残しては置く。 + +2022-03-12 + + * prompt: bash-5.2 では \w, \W に加えて \s についても escape する様だ [#D1801] + Ref #D1798 + + bash がなかなか実装しないと思ったらこちらが \w, \W に対する実装を push した + 4日後に対応が入った。どうも \s についても escape が入ったという様に commit + message には書かれている。 + + \s は "bash" という文字列の様だ。これに制御文字が含まれるとは一体どういう状 + 況だろうか。これを気にするのであれば \h, \H, \u も気にするべきなのではない + か。取り敢えず全てに大して対策を加える事にした。 + + ? bash-5.2 では ${PS1@P} でもちゃんと \w, \W を escape してくれるのか→ちゃ + んと escape してくれている。 + + * done: bash-4.4 以上では escape が起こった時に @P を使わない自前実装に切り + 替える必要がある。 + + * bash-5.2 の実装についても改めて確認する。\t はそのまま特殊文字のまま出力 + する様だ。その他については zsh の様に \n だとか \t の様な表現には置き換え + ず一貫して ^X という形で表現している。改行は ^J になっている。 + + \s 以外にも対応している物がないか確認する。 + + bash-5.2 の対応では sh_backslash_quote_for_double_quotes に手を入れる事に + よって対応が行われている。この関数は本来は eval する時に変な事が起こらな + い様に $`"\ 等を escape するのが目的だったのだと思われるが、同時にエスケー + プまで実行してしまうという算段である。 + + 特にこの機能が有効になるのは第二引数に bit 1 を指定した時で以下が該当する。 + + ./parse.y:5745: temp = sh_backslash_quote_for_double_quotes (temp, 1); + ./parse.y:5822: temp = sh_backslash_quote_for_double_quotes (t_string, 1); + + そしてこれは正に commit msg にある様にそれぞれ \s と \w\W に対する処理で + あった。なので \s, \w, \W 以外に関しては対策は実装されていない。 + + ? うーん。 ^\ に大して何か変な事が起こったりするのではないか…。例えば + ^\$(echo hello) が実行されてしまう可能性はないのだろうか。試してみたら + 問題を再現できてしまった。 + + $ mkdir $'\034$(echo hello)' + $ cd !$ + + ? これは shopt -u promptvars でもちゃんと実行されるのだろうか? →試してみ + たがちゃんと動いている様だ。OK + + 2022-03-19 これは bash に PATCH を送ったら今日適用されていた。OK + + * bash-5.2 では META_CHAR に対しても escape を実装している様だ。うーん。 + ble.sh でも対応するべきだろうか。と思ったがよく考えてみたら ble.sh ではそ + もそも編集文字列であっても 80..A0 に対して特別な文字は割り当てていない様 + な気もする。これはそれも含めて再考する必要がある。 + + →と思ったが改めて確認してみたところ + _ble_unicode_GraphemeCluster_ControlRepresentation という配列にちゃんと登 + 録しているのだった。この新しい実装でもこの配列を参照するべきである。 + + と思ったが _ble_unicode_GraphemeCluster_ControlRepresentation は単にキャッ + シュしているだけなので代わりに ble/unicode/GraphemeCluster/.get-ascii-rep + を呼び出すべきである。その様に実装し直した。 + 2022-03-04 * 2021-10-26 ble/builtin/read: status が表示されている気がする [#D1800] diff --git a/src/edit.sh b/src/edit.sh index d035bc74..8eae5a50 100644 --- a/src/edit.sh +++ b/src/edit.sh @@ -465,31 +465,79 @@ function ble/prompt/status#collapse { _ble_prompt_hash= _ble_prompt_version=0 +function ble/prompt/.escape-control-characters { + ret=$1 + local glob_ctrl=$'[\001-\037\177-\237]' + [[ $ret == *$glob_ctrl* ]] || return 0 + + local out= head tail=$ret cs + while head=${tail%%$glob_ctrl*}; [[ $head != "$tail" ]]; do + ble/util/s2c "${tail:${#head}:1}" + ble/unicode/GraphemeCluster/.get-ascii-rep "$ret" # -> cs + out=$out$head$'\e[9807m'$cs$'\e[9807m' + tail=${tail#*$glob_ctrl} + done + ret=$out$tail +} + +## @fn ble/prompt/.initialize-constant ps defeval [opts] +## @param ps +## 初期化に使用する prompt シーケンスを指定します。 +## @param defeval +## 初期化に使用するコマンドを指定します。ret に結果を格納します。 +## @param[opt] opts +## コロン区切りのオプションリストです。escape が指定されている時、 +## 展開結果に含まれる制御文字をエスケープします。 +function ble/prompt/.initialize-constant { + local __ps=$1 __defeval=$2 __opts=$3 + if ((_ble_bash>=40400)); then + ret=${__ps@P} + else + builtin eval -- "$__defeval" + fi + + if [[ $__opts == *:escape:* ]]; then + if ((_ble_bash>=50200)); then + # bash-5.2 以上では bash が escape を行うが、反転などの処理が実 + # 装されていないので、制御文字が含まれている場合には ble.sh の側 + # で処理を行う。 + if [[ $ret == *\^['A'-'Z[\]^_?']* ]]; then + builtin eval -- "$__defeval" + ble/prompt/.escape-control-characters "$ret" + elif [[ $ret == *$'\t'* ]]; then + ble/prompt/.escape-control-characters "$ret" + fi + else + ble/prompt/.escape-control-characters "$_ble_prompt_const_s" + fi + fi +} + ## called by ble-edit/initialize function ble/prompt/initialize { + local ret + # hostname - _ble_prompt_const_H=${HOSTNAME} + ble/prompt/.initialize-constant '\H' 'ret=$HOSTNAME' escape + _ble_prompt_const_H=$ret if local rex='^[0-9]+(\.[0-9]){3}$'; [[ $HOSTNAME =~ $rex ]]; then # IPv4 の形式の場合には省略しない - _ble_prompt_const_h=$HOSTNAME + _ble_prompt_const_h=$_ble_prompt_const_H else - _ble_prompt_const_h=${HOSTNAME%%.*} + _ble_prompt_const_h=${_ble_prompt_const_H%%.*} fi # tty basename - local tmp - if ((_ble_bash>=40400)); then - tmp='\l' _ble_prompt_const_l=${tmp@P} - else - ble/util/assign tmp 'ble/bin/tty 2>/dev/null' - _ble_prompt_const_l=${tmp##*/} - fi + ble/prompt/.initialize-constant '\l' 'ble/util/assign ret "ble/bin/tty 2>/dev/null";ret=${ret##*/}' + _ble_prompt_const_l=$ret # command name - _ble_prompt_const_s=${0##*/} + ble/prompt/.initialize-constant '\s' 'ret=${0##*/}' escape + _ble_prompt_const_s=$ret # user - _ble_prompt_const_u=${USER} + ble/prompt/.initialize-constant '\s' 'ret=$USER' escape + _ble_prompt_const_u=$ret # bash versions ble/util/sprintf _ble_prompt_const_v '%d.%d' "${BASH_VERSINFO[0]}" "${BASH_VERSINFO[1]}" @@ -897,26 +945,11 @@ function ble/prompt/backslash:V { # = bash version %d.%d.%d ble/prompt/print "$_ble_prompt_const_V" return 0 } -function ble/prompt/backslash/.escape-control-characters { - ret=$1 - local glob_ctrl=$'[\001-\037\177]' - [[ $ret == *$glob_ctrl* ]] || return 0 - - local out= head tail=$ret - while head=${tail%%$glob_ctrl*}; [[ $head != "$tail" ]]; do - out=$out$head - ble/util/s2c "${tail:${#head}:1}" - ble/util/c2s $((ret<32?ret+64:63)) - out=$out$'\e[9807m'^$ret$'\e[9807m' - tail=${tail#*$glob_ctrl} - done - ret=$out$tail -} function ble/prompt/backslash:w { # PWD ble/prompt/unit/add-hash '$PWD' ble/prompt/.update-working-directory local ret - ble/prompt/backslash/.escape-control-characters "$prompt_cache_wd" + ble/prompt/.escape-control-characters "$prompt_cache_wd" ble/prompt/print "$ret" return 0 } @@ -927,7 +960,7 @@ function ble/prompt/backslash:W { # PWD短縮 else ble/prompt/.update-working-directory local ret - ble/prompt/backslash/.escape-control-characters "${prompt_cache_wd##*/}" + ble/prompt/.escape-control-characters "${prompt_cache_wd##*/}" ble/prompt/print "$ret" fi return 0 @@ -1178,6 +1211,27 @@ function ble/prompt/.get-keymap-for-current-mode { keymap=${_ble_decode_keymap_stack[index]} done } + +function ble/prompt/.uses-builtin-prompt-expansion { + ((_ble_bash>=40400)) || return 1 + + local ps=$1 + local chars_safe_esc='][0-7aenrdtAT@DhHjlsuvV!$\wW' + [[ ( $OSTYPE == cygwin || $OSTYPE == msys ) && $_ble_prompt_const_root == '#' ]] && + chars_safe_esc=${chars_safe_esc//'$'} # Note: cygwin では ble.sh 独自の方法で \$ を処理する。 + + [[ $ps == *'\'[!"$chars_safe_esc"]* ]] && return 1 + + local glob_ctrl=$'[\001-\037\177]' + [[ $ps == *'\'[wW]* && $PWD == *$glob_ctrl* ]] && return 1 + [[ $ps == *'\s'* && $_ble_prompt_const_s == *$'\e'* ]] && return 1 + [[ $ps == *'\u'* && $_ble_prompt_const_u == *$'\e'* ]] && return 1 + [[ $ps == *'\h'* && $_ble_prompt_const_h == *$'\e'* ]] && return 1 + [[ $ps == *'\H'* && $_ble_prompt_const_H == *$'\e'* ]] && return 1 + + return 0 +} + ## @fn ble/prompt/.instantiate ps opts [x0 y0 g0 lc0 lg0 esc0 trace_hash0] ## ## @var[out] x y g @@ -1202,10 +1256,7 @@ function ble/prompt/.instantiate { [[ ! $ps ]] && return 0 local expanded= - local chars_safe_esc='][0-7aenrdtAT@DhHjlsuvV!$\wW' - [[ ( $OSTYPE == cygwin || $OSTYPE == msys ) && $_ble_prompt_const_root == '#' ]] && - chars_safe_esc=${chars_safe_esc//'$'} # Note: cygwin では ble.sh 独自の方法で \$ を処理する。 - if ((_ble_bash>=40400)) && [[ $ps != *'\'[!"$chars_safe_esc"]* && ! ( $ps == *'\'[wW]* && $PWD == *[$'\001'-$'\037\177']* ) ]]; then + if ble/prompt/.uses-builtin-prompt-expansion "$ps"; then [[ $ps == *'\'[wW]* ]] && ble/prompt/unit/add-hash '$PWD' ble-edit/exec/.setexit "$_ble_edit_exec_lastarg" BASH_COMMAND=$_ble_edit_exec_BASH_COMMAND \