180 lines
6.8 KiB
Bash
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"}; }
|