bash/.local/share/blesh/contrib/bash-preexec.bash
2024-08-18 03:40:38 +02:00

180 lines
6.8 KiB
Bash

# ble/contrib/integration/bash-preexec.bash (C) 2022-2023, akinomyoga
## @arr[in] precmd_functions
## @arr[in] preexec_functions
## The functions registered to these arrays are executed on PRECMD and
## PREEXEC hooks, respectively.
##
## @fn[in] precmd
## @fn[in] preexec
## If these functions are defined, they are executed on PRECMD and PREEXEC
## hooks, respectively, through "precmd_functions" and "preexec_functions".
##
##
## * Integration with bash-preexec.sh (https://github.com/rcaloras/bash-preexec)
##
## Although this script works without bash-preexec, it provides a better
## integration with bash-preexec when bash-preexec is loaded. The
## integration relies on the following public API of bash-preexec.
##
## @fn __bp_precmd_invoke_functions lastexit lastarg
## @fn __bp_preexec_invoke_functions lastexit lastarg this_command
## @fn __bp_uninstall
## @var __bp_trapdebug_string
## @var __bp_install_string
function ble/contrib/integration:bash-preexec/add-convenience-functions {
ble/array#remove precmd_functions precmd
ble/array#remove preexec_functions preexec
ble/array#unshift precmd_functions precmd
ble/array#unshift preexec_functions preexec
}
function ble/contrib/integration:bash-preexec/precmd.hook {
local _ble_local_lastexit=$? _ble_local_lastarg=$_
# Emulate bash-preexec variables
__bp_last_ret_value=$_ble_local_lastexit
__bp_last_argument_prev_command=$_ble_local_lastarg
BP_PIPESTATUS=("${BLE_PIPESTATUS[@]}")
local __bp_inside_precmd=1
# local __bp_blesh_invoking_through_blesh=1 # XXX
if ble/is-function __bp_precmd_invoke_functions; then
__bp_precmd_invoke_functions "$_ble_local_lastexit" "$_ble_local_lastarg"
else
# For older bash-preexec.sh / without bash-preexec.sh
local _ble_local_hook
for _ble_local_hook in "${precmd_functions[@]}"; do
if ble/bin#has "$_ble_local_hook"; then
ble/util/setexit "$_ble_local_lastexit" "$_ble_local_lastarg"
"$_ble_local_hook"
fi
done
fi
}
function ble/contrib/integration:bash-preexec/preexec.hook {
local _ble_local_lastexit=$? _ble_local_lastarg=$_ _ble_local_command=$1
# Emulate bash-preexec variables
local __bp_inside_preexec=1
# local __bp_blesh_invoking_through_blesh=1 # XXX
if ble/is-function __bp_preexec_invoke_functions; then
__bp_preexec_invoke_functions "$_ble_local_lastexit" "$_ble_local_lastarg"
else
# For older bash-preexec.sh / without bash-preexec.sh
local _ble_local_hook
for _ble_local_hook in "${preexec_functions[@]}"; do
if ble/bin#has "$_ble_local_hook"; then
ble/util/setexit "$_ble_local_lastexit" "$_ble_local_lastarg"
"$_ble_local_hook" "$_ble_local_command"
fi
done
fi
}
## @fn ble/contrib/integration:bash-preexec/attach.hook
## Remove bash-preexec hooks
function ble/contrib/integration:bash-preexec/attach.hook {
local BP_TRAPDEBUG_STRING=${__bp_trapdebug_string:-'__bp_preexec_invoke_exec "$_"'}
# Remove bash-preexec preexec hook in builtin DEBUG trap.
local trap_string q="'" Q="'\''"
ble/util/assign trap_string 'builtin trap -p DEBUG'
if [[ $trap_string == "trap -- '${BP_TRAPDEBUG_STRING//$q/$Q}' DEBUG" ]]; then
if [[ ${__bp_trap_string-} ]]; then
builtin eval -- "builtin $__bp_trap_string"
else
builtin trap - DEBUG
fi
fi
if ble/is-function __bp_uninstall; then
__bp_uninstall
else
# For older bash-preexec.sh
local BP_INSTALL_STRING=${__bp_install_string:-$'__bp_trap_string="$(trap -p DEBUG)"\ntrap - DEBUG\n__bp_install'}
local BP_PROMPT_COMMAND_PREFIX=__bp_precmd_invoke_cmd
local BP_PROMPT_COMMAND_SUFFIX=__bp_interactive_mode
# Remove __bp_install hook from PROMPT_COMMAND
if [[ ${PROMPT_COMMAND-} == *"$__bp_install_string"* ]]; then
PROMPT_COMMAND="${PROMPT_COMMAND//$BP_INSTALL_STRING[;$'\n']}" # Edge case of appending to PROMPT_COMMAND
PROMPT_COMMAND="${PROMPT_COMMAND//$BP_INSTALL_STRING}"
fi
# Remove precmd hook from PROMPT_COMMAND
local i prompt_command
for i in "${!PROMPT_COMMAND[@]}"; do
prompt_command=${PROMPT_COMMAND[i]}
case $prompt_command in
("$BP_PROMPT_COMMAND_PREFIX"|"$BP_PROMPT_COMMAND_SUFFIX")
prompt_command= ;;
(*)
prompt_command=${prompt_command/#"$BP_PROMPT_COMMAND_PREFIX"$'\n'/$'\n'}
prompt_command=${prompt_command%$'\n'"$BP_PROMPT_COMMAND_SUFFIX"}
prompt_command=${prompt_command#$'\n'}
esac
PROMPT_COMMAND[i]=$prompt_command
done
# Remove preexec hook in the DEBUG trap
local q="'" Q="'\''" trap_string
ble/util/assign trap_string 'trap -p DEBUG'
if [[ $trap_string == "trap -- '${BP_TRAPDEBUG_STRING//$q/$Q}' DEBUG" ]]; then
if [[ ${__bp_trap_string-} ]]; then
builtin eval -- "$__bp_trap_string"
else
trap - DEBUG
fi
fi
fi
}
ble/function#trace ble/contrib/integration:bash-preexec/attach.hook
## @fn ble/contrib/integration:bash-preexec/detach.hook
function ble/contrib/integration:bash-preexec/detach.hook {
# Reinstall bash-preexec hooks
local BP_INSTALL_STRING=${__bp_install_string-}
[[ ! $BP_INSTALL_STRING ]] && ble/is-function __bp_install &&
BP_INSTALL_STRING=$'__bp_trap_string="$(trap -p DEBUG)"\ntrap - DEBUG\n__bp_install'
builtin eval -- "$__bp_install_string"
# Note: 重複して登録される (古い bash-preexec.sh) かもしれないし、全
# く登録されない (bash-preexec.sh をロードしていない時) かもしれない
# ので、ble.sh 側で末尾で一回呼び出す形に修正する。
ble/contrib/integration:bash-preexec/add-convenience-functions
}
ble/contrib/integration:bash-preexec/add-convenience-functions
blehook PRECMD!=ble/contrib/integration:bash-preexec/precmd.hook
blehook PREEXEC!=ble/contrib/integration:bash-preexec/preexec.hook
blehook ATTACH!=ble/contrib/integration:bash-preexec/attach.hook
blehook DETACH!=ble/contrib/integration:bash-preexec/detach.hook
if [[ ${bash_preexec_imported-${__bp_imported-}} ]]; then
ble/contrib/integration:bash-preexec/attach.hook
fi
# prevent bash-preexec.sh to be loaded
blehook ATTACH-=ble/contrib/integration:bash-preexec/loader
blehook POSTEXEC-=ble/contrib/integration:bash-preexec/loader
bash_preexec_imported=defined
__bp_imported=defined
# XXX: 以下は uninstall で削除しきれなかった時の為の保険。今の所不要に思われる。
# __bp_blesh_check() {
# if [[ $BLE_ATTACHED && ! ${__bp_blesh_invoking_through_blesh-} ]]; then
# ble/contrib/integration:bash-preexec/attach.hook
# fi
# }
# precmd_function+=(__bp_blesh_check)
# preexec_function+=(__bp_blesh_check)
# Some settings rely on the internal APIs of bash-preexec. For example, iTerm2
# shell integration uses "__bp_set_ret_value" and
# "$__bp_last_argument_prev_command".
function __bp_set_ret_value { return ${1:+"$1"}; }