Skip to content

Commit

Permalink
prompt: reduce redundant evaluation of "PROMPT_COMMAND" on the startup
Browse files Browse the repository at this point in the history
  • Loading branch information
akinomyoga committed Feb 19, 2022
1 parent 398e404 commit 042376b
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 34 deletions.
47 changes: 41 additions & 6 deletions ble.pp
Expand Up @@ -1600,28 +1600,49 @@ function ble/base/install-prompt-attach {
fi
fi
}
_ble_base_attach_from_prompt_lastexit=
_ble_base_attach_from_prompt_lastarg=
_ble_base_attach_from_prompt_PIPESTATUS=()
## @fn ble/base/attach-from-PROMPT_COMMAND prompt_command lambda
function ble/base/attach-from-PROMPT_COMMAND {
#%if measure_load_time
ble/util/print "ble.sh: $EPOCHREALTIME start prompt-attach" >&2
#%end
# 後続の設定によって PROMPT_COMMAND が置換された場合にはそれを保持する
{
# save $?, $_ and ${PIPE_STATUS[@]}
_ble_base_attach_from_prompt_lastexit=$? \
_ble_base_attach_from_prompt_lastarg=$_ \
_ble_base_attach_from_prompt_PIPESTATUS=("${PIPESTATUS[@]}")
#%if measure_load_time
ble/util/print "ble.sh: $EPOCHREALTIME start prompt-attach" >&2
#%end
if ((BASH_LINENO[${#BASH_LINENO[@]}-1]>=1)); then
# 既にコマンドを実行している時にはそのコマンドの結果を記録する
_ble_edit_exec_lastexit=$_ble_base_attach_from_prompt_lastexit
_ble_edit_exec_lastarg=$_ble_base_attach_from_prompt_lastarg
_ble_edit_exec_PIPESTATUS=("${_ble_base_attach_from_prompt_PIPESTATUS[@]}")
# Note: 本当は一つ前のコマンドを知りたいが確実な方法がないのでこの関数の名前を入れておく。
_ble_edit_exec_BASH_COMMAND=$FUNCNAME
fi

local is_last_PROMPT_COMMAND=1
if (($#==0)); then
ble/array#replace PROMPT_COMMAND ble/base/attach-from-PROMPT_COMMAND
if local ret; ble/array#index PROMPT_COMMAND ble/base/attach-from-PROMPT_COMMAND; then
local keys; keys=("${!PROMPT_COMMAND[@]}")
((ret==keys[${#keys[@]}-1])) || is_last_PROMPT_COMMAND=
ble/idict#replace PROMPT_COMMAND ble/base/attach-from-PROMPT_COMMAND
fi
blehook PRECMD-=ble/base/attach-from-PROMPT_COMMAND || ((1)) # set -e 対策
else
local save_index=$1 lambda=$2

# 待避していた内容を復元・実行
local PROMPT_COMMAND_local=
[[ $PROMPT_COMMAND == "$lambda" ]] || local PROMPT_COMMAND PROMPT_COMMAND_local=1
[[ $PROMPT_COMMAND == "$lambda" ]] || local PROMPT_COMMAND is_last_PROMPT_COMMAND=
PROMPT_COMMAND=${_ble_base_attach_PROMPT_COMMAND[save_index]}
local ble_base_attach_from_prompt_command=processing
ble/prompt/update/.eval-prompt_command 2>&3
ble/util/unlocal ble_base_attach_from_prompt_command
_ble_base_attach_PROMPT_COMMAND[save_index]=$PROMPT_COMMAND
[[ ! $PROMPT_COMMAND_local ]] || ble/util/unlocal PROMPT_COMMAND
[[ $is_last_PROMPT_COMMAND ]] || ble/util/unlocal PROMPT_COMMAND
blehook PRECMD-="$lambda" || ((1)) # set -e 対策

# #D1354: 入れ子の ble/base/attach-from-PROMPT_COMMAND の時は一番
Expand All @@ -1633,6 +1654,20 @@ function ble/base/attach-from-PROMPT_COMMAND {
# 既に attach 状態の時は処理はスキップ
[[ $_ble_base_attach_from_prompt ]] || return 0
_ble_base_attach_from_prompt=

# Note #D1778: この attach-from-PROMPT_COMMAND が PROMPT_COMMAND
# 処理の最後と見做せる場合、この時点で PROMPT_COMMAND は一通り終
# わったと見做せるので、ble-attach 内部で改めて PROMPT_COMMAND
# を実行する必要はなくなる。それを伝える為に中間状態の
# _ble_prompt_hash の値を設定する。
# Note #D1778: bash-preexec 経由でプロンプトを設定しようとしている
# 場合は、この時点で既に PRECMD に hook が移動している可能性があ
# るので PRECMD も発火しておく (PROMPT_COMMAND と PRECMD の順序
# が逆になるが仕方がない。問題になれば後で考える)。
if [[ $is_last_PROMPT_COMMAND ]]; then
ble-edit/exec:gexec/invoke-hook-with-setexit PRECMD
_ble_prompt_hash=$COLUMNS:$_ble_edit_lineno:prompt_attach
fi
} 3>&2 2>/dev/null # set -x 対策 #D0930

ble-attach force
Expand Down
9 changes: 5 additions & 4 deletions docs/ChangeLog.md
Expand Up @@ -90,8 +90,8 @@
- complete (menu-style:align): refactor `complete_menu_align => menu_align_{min,max}` (motivated by banoris) `#D1717` 22a2449
- prompt: support `bleopt prompt_command_changes_layout` `#D1750` e199bee
- exec: measure execution times `#D1756` 2b28bec
- edit: work around a bash-4.4..5.1 bug of `exit` outputting time to stderr of exit context `#D1765` 3de751e 0000000
- util: preserve original traps and restore them on unload `#D1775` `#D1776` `#D1777` 0000000
- edit: work around a bash-4.4..5.1 bug of `exit` outputting time to stderr of exit context `#D1765` 3de751e e61dbaa
- util: preserve original traps and restore them on unload `#D1775` `#D1776` `#D1777` 398e404

## Changes

Expand Down Expand Up @@ -269,6 +269,7 @@
- decode: cache `inputrc` translations `#D1652` 994e2a5
- complete: use `awk` for batch `quote-insert` (motivated by banoris) `#D1714` a0b2ad2 92d9734
- complete (quote-insert.batch): fix regex escaping in bracket expr of awk (reported by telometto) `#D1729` 8039b77
- prompt: reduce redundant evaluation of `PROMPT_COMMAND` on the startup `#D1778` 0000000

## Compatibility

Expand Down Expand Up @@ -319,8 +320,8 @@
- main: check `/dev/tty` on startup (reported by andychu) `#D1749` 711c69f
- util: add identification of Windows Terminal `wt` `#D1758` e332dc5
- complete: evaluate words for `noquote` (motivated by SuperSandro2000) `#D1767` 0a42299
- edit (TRAPDEBUG): preserve original `DEBUG` trap and enabled it in `PROMPT_COMMAND` (motivated by ammarooo) `#D1772` `#D1773` 0000000
- global: work around bash-3.0 bug that single quotas remains for `"${v-$''}"` `#D1774` 0000000
- edit (TRAPDEBUG): preserve original `DEBUG` trap and enabled it in `PROMPT_COMMAND` (motivated by ammarooo) `#D1772` `#D1773` ec2a67a
- global: work around bash-3.0 bug that single quotas remains for `"${v-$''}"` `#D1774` 9b96578

## Internal changes and fixes

Expand Down
6 changes: 3 additions & 3 deletions lib/core-syntax.sh
Expand Up @@ -756,7 +756,7 @@ function ble/syntax/parse/word-cancel {
local wlen=${word[1]} tplen=${word[3]}
local wbegin=$((i-wlen))
tchild=$((tplen<0?tplen:i-tplen))
ble/dense-array#fill-range _ble_syntax_tree "$wbegin" "$i" ''
ble/array#fill-range _ble_syntax_tree "$wbegin" "$i" ''
}

# 入れ子構造の管理
Expand Down Expand Up @@ -7171,7 +7171,7 @@ function ble/highlight/layer:syntax/word/.apply-attribute {
wbeg<wend)) || return 1

if [[ $wattr =~ ^[0-9]+$ ]]; then
ble/dense-array#fill-range _ble_highlight_layer_syntax2_table "$wbeg" "$wend" "$wattr"
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
Expand All @@ -7186,7 +7186,7 @@ function ble/highlight/layer:syntax/word/.apply-attribute {
(((i=j)<wend)) || break
done
elif [[ $wattr == d ]]; then
ble/dense-array#fill-range _ble_highlight_layer_syntax2_table "$wbeg" "$wend" ''
ble/array#fill-range _ble_highlight_layer_syntax2_table "$wbeg" "$wend" ''
fi
}

Expand Down
1 change: 1 addition & 0 deletions make_command.sh
Expand Up @@ -1324,6 +1324,7 @@ function sub:scan {
\Zlocal trap_command="trap -- Zd
\Zlocal trap$Zd
\Z\$\{content#"trap -- '\''"\}Zd
\Z\("trap -- '\''.*"\*\)Zd
g'

sub:scan/a.txt
Expand Down
66 changes: 63 additions & 3 deletions note.txt
Expand Up @@ -6115,6 +6115,65 @@ bash_tips

2022-02-17

* main, edit: 起動時に無駄に PROMPT_COMMAND が実行されるのを防げないか [#D1778]

PS1 に含まれるコマンド置換も同様である。画面サイズが変わる等しない限りは再
計算する必要はない筈である。

今試してみたがそれほど無駄に実行している訳でもない様に思われる。

* 但し、_ble_history_count が初期化される前と初期化された後で
PROMPT_COMMAND が再計算されていたのは修正する事にした。これで恐らく起動時
刻も短くなったのではないかと思われる。これで1回実行が減少した。

* 実は #D1772 の時点で既に1回実行を減らしている筈である。PROMPT_COMMAND を
待避した事によって減っていると期待する。しかし本当にこれで減ったのだろう
か。怪しい → 試して見た所 manual attach の時に回数を一回減らす事ができて
いると判明した。

これで合計で4回実行されていた #D1772 の状況を再現できた。更に減らす事は可能
だろうか。現在 prompt-attach を使っているが、ble-attach の時にはもっと減っ
ても良いのではないか? → 確認してみると manual attach の時には
_ble_history_count が bashrc の中で 1 で、その後で実際の数に増えるという事
の様である。

* うーん。そもそも PROMPT_COMMAND の決定に _ble_history_count が影響を与え
るのだろうか。というのは疑問である。実は PROMPT_COMMAND に関しては
_ble_history_count に関係なく version を決めて良いのではないか?

→その様に変更する事にした。これで manual attach ならば唯1回の
PROMPT_COMMAND の実行になった。

一方で PS1 の評価に関しては history count が影響を与えるので
_ble_history_count が変化したらちゃんと再評価しなければならない。これが二
重に評価されるのは仕方がないと諦める事にする。

* prompt attach の場合には依然として二重に PROMPT_COMMAND が実行されている。
うーん。PROMPT_COMMAND が書き換えられて直接削除できない場合は仕方がないと
して、内部で実行している場合には呼び出しを省略できないのか。と思ったが、
PROMPT_COMMAND 配列の時には結局 bash は全てを実行するし、或いは、内部で保
持している物についてはその場で実行しておかないと bash-preexec.sh の様に内
部で PROMPT_COMMAND を書き換える様な物に対して矛盾のない動作を提供する事
ができない。或いはもっと注意深く考察すれば何かできるのかもしれないが。

或いは逆に ble-attach の中で実行している PROMPT_ATTACH の方を省略させる?
と思ったが、

x その場合 PROMPT_COMMAND 配列でより後にある PROMPT_COMMAND の実行結果が
反映されない事になるし、ble-attach の処理が終わった後に続きで実行される
PROMPT_COMMAND を阻止する事は結局できない。

とは言いつつも scalar PROMPT_COMMAND (他によって修正されていない) または
"配列 PROMPT_COMMAND かつ最終要素" の場合には、続きで別の処理が走らないと
いう事は保証できるので、ble-attach の内部で走る PROMPT_ATTACH は省略でき
る。

2022-02-19 うーん。bash-it のプロンプトが prompt attach で初期化されなくなっ
た。どうやら bash-preexec precmd 経由で bash-it は設定を行っている様で、
bash-preexec が ble.sh によって置き換えられた事によって precmd が実行されな
くなっているのが原因の様だ。うーん。precmd は実行しておくべきの気がしてきた。
→取り敢えず PRECMD を呼び出す様にしたら期待通りに動く様になった。

* 2020-09-01 trap: ble.sh を unload する時に復元する仕組みがあっても良いのではないか [#D1777]
#D1775 と同時に対応した。

Expand Down Expand Up @@ -7030,9 +7089,10 @@ bash_tips
* 後に ble.sh を source した場合には以下の場合にロード直後は DEBUG trap が
ble.sh 内部の処理に対しても有効になっている。

- rcfile が .bashrc でも .profile でも .bash_profile でもない場合 (これ
は現在 rcfile の中にいるかどうかを判定する方法が bash にはない事から、
rcfile かどうかをファイル名と行番号だけから判定しなければならない事に
- (set -T & --attach=attach の時の条件) rcfile が .bashrc でも
.profile でも .bash_profile でもない場合 (これは現在 rcfile の
中にいるかどうかを判定する方法が bash にはない事から、rcfile
かどうかをファイル名と行番号だけから判定しなければならない事に
由来する)

- source ~/.bashrc 等の様にして手動で bashrc を読み込んだ時 (これは
Expand Down
2 changes: 1 addition & 1 deletion src/canvas.sh
Expand Up @@ -3117,7 +3117,7 @@ function ble/canvas/panel/invalidate {
ble/canvas/excursion-end.draw
ble/canvas/put.draw "$_ble_term_cr$_ble_term_ed"
_ble_canvas_x=0 _ble_canvas_y=0
ble/dense-array#fill-range _ble_canvas_panel_height 0 "${#_ble_canvas_panel_height[@]}" 0
ble/array#fill-range _ble_canvas_panel_height 0 "${#_ble_canvas_panel_height[@]}" 0
ble/canvas/panel/reallocate-height.draw
ble/canvas/bflush.draw
fi
Expand Down
6 changes: 4 additions & 2 deletions src/edit.sh
Expand Up @@ -1539,7 +1539,8 @@ _ble_prompt_rps1_enabled=
function ble/prompt/update {
local opts=:$1: dirty=

local version=$COLUMNS:$_ble_edit_lineno:$_ble_history_count
local count; ble/history/get-count
local version=$COLUMNS:$_ble_edit_lineno:$count
if [[ :$opts: == *:check-dirty:* && $_ble_prompt_update == owner ]]; then
if [[ $_ble_prompt_update_dirty && :$opts: != *:leave:* && $_ble_prompt_hash == "$version" ]]; then
[[ $_ble_prompt_update_dirty == dirty ]]; local ext=$?
Expand All @@ -1554,7 +1555,8 @@ function ble/prompt/update {

# Update PS1 in PROMPT_COMMAND / PRECMD
if ((_ble_textarea_panel==0)); then # 補助プロンプトに対しては PROMPT_COMMAND は実行しない
if [[ $_ble_prompt_hash != "$version" && $opts != *:leave:* ]]; then
# Note #D1778: version の内の history count は PROMPT_COMMAND の更新には使わない。
if [[ ${_ble_prompt_hash%:*} != "${version%:*}" && $opts != *:leave:* ]]; then
if ble/prompt/update/.has-prompt_command || blehook/has-hook PRECMD; then
# #D1750 PROMPT_COMMAND 及び PRECMD が何か出力する時は表示が乱れるので
# クリアする。点滅などを避ける為、既定では off にしておく。
Expand Down
29 changes: 14 additions & 15 deletions src/util.sh
Expand Up @@ -728,8 +728,8 @@ function ble/array#index {
local _ble_local_script='
local eARR iARR=0
for eARR in "${ARR[@]}"; do
[[ $eARR == "$2" ]] && { ret=$iARR; return 0; }
((iARR++))
if [[ $eARR == "$2" ]]; then ret=$iARR; return 0; fi
((++iARR))
done
ret=-1; return 1
'; builtin eval -- "${_ble_local_script//ARR/$1}"
Expand All @@ -745,20 +745,29 @@ function ble/array#last-index {
ret=-1; return 1
'; builtin eval -- "${_ble_local_script//ARR/$1}"
}
## @fn ble/array#remove arr index
## @fn ble/array#remove-at arr index
function ble/array#remove-at {
local _ble_local_script='
builtin unset -v "ARR[$2]"
ARR=("${ARR[@]}")
'; builtin eval -- "${_ble_local_script//ARR/$1}"
}
## @fn ble/array#replace arr needle [replacement]
function ble/array#fill-range {
ble/array#reserve-prototype $(($3-$2))
local _ble_script='
local -a sARR; sARR=("${_ble_array_prototype[@]::$3-$2}")
ARR=("${ARR[@]::$2}" "${sARR[@]/#/$4}" "${ARR[@]:$3}")' # WA #D1570 #D1738 checked
((_ble_bash>=40300)) && ! shopt -q compat42 &&
_ble_script=${_ble_script//'$4'/'"$4"'}
builtin eval -- "${_ble_script//ARR/$1}"
}
## @fn ble/idict#replace arr needle [replacement]
## needle に一致する要素を全て replacement に置換します。
## replacement が指定されていない時は該当要素を unset します。
## @var[in] arr
## @var[in] needle
## @var[in,opt] replacement
function ble/array#replace {
function ble/idict#replace {
local _ble_local_script='
local iARR=0 extARR=1
for iARR in "${!ARR[@]}"; do
Expand All @@ -774,16 +783,6 @@ function ble/array#replace {
'; builtin eval -- "${_ble_local_script//ARR/$1}"
}

function ble/dense-array#fill-range {
ble/array#reserve-prototype $(($3-$2))
local _ble_script='
local -a sARR; sARR=("${_ble_array_prototype[@]::$3-$2}")
ARR=("${ARR[@]::$2}" "${sARR[@]/#/$4}" "${ARR[@]:$3}")' # WA #D1570 #D1738 checked
((_ble_bash>=40300)) && ! shopt -q compat42 &&
_ble_script=${_ble_script//'$4'/'"$4"'}
builtin eval -- "${_ble_script//ARR/$1}"
}

function ble/idict#copy {
local _ble_script='
'$1'=()
Expand Down

0 comments on commit 042376b

Please sign in to comment.