From 47d841d7b5262bb382c7204ee70fb00afc399f91 Mon Sep 17 00:00:00 2001 From: Koichi Murase Date: Thu, 9 Jan 2025 19:20:12 +0900 Subject: [PATCH] Use PS0 and function substitution in Bash 5.3 --- bash-preexec.sh | 39 ++++++++++++++++++++++++++++++++------- test/bash-preexec.bats | 7 +++++-- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/bash-preexec.sh b/bash-preexec.sh index 236c8a4..38a4c8f 100644 --- a/bash-preexec.sh +++ b/bash-preexec.sh @@ -291,6 +291,15 @@ __bp_preexec_invoke_exec() { __bp_set_ret_value "$preexec_ret_value" "$__bp_last_argument_prev_command" } +__bp_invoke_preexec_from_ps0() { + __bp_last_argument_prev_command="${1:-}" + + local this_command + __bp_load_this_command_from_history || return + + __bp_invoke_preexec_functions "${__bp_last_ret_value:-}" "$__bp_last_argument_prev_command" "$this_command" +} + # This function invokes every function defined in our function array # "preexec_function". This function receives the arguments $1 and $2 for $? # and $_, respectively, which will be set for each preexec function. The third @@ -320,12 +329,7 @@ __bp_invoke_preexec_functions() { __bp_set_ret_value "$preexec_ret_value" } -__bp_install() { - # Exit if we already have this installed. - if [[ "${PROMPT_COMMAND[*]:-}" == *"__bp_precmd_invoke_cmd"* ]]; then - return 1; - fi - +__bp_hook_preexec_into_debug() { local trap_string trap_string=$(trap -p DEBUG) trap '__bp_preexec_invoke_exec "$_"' DEBUG @@ -355,6 +359,27 @@ __bp_install() { set -o functrace > /dev/null 2>&1 shopt -s extdebug > /dev/null 2>&1 fi; +} + +__bp_hook_preexec_into_ps0() { + # shellcheck disable=SC2016 + PS0=${PS0-}'${ __bp_invoke_preexec_from_ps0 "$_"; }' + + # Adjust our HISTCONTROL Variable if needed. + __bp_adjust_histcontrol +} + +__bp_install() { + # Exit if we already have this installed. + if [[ "${PROMPT_COMMAND[*]:-}" == *"__bp_precmd_invoke_cmd"* ]]; then + return 1; + fi + + if (( BASH_VERSINFO[0] > 5 || (BASH_VERSINFO[0] == 5 && BASH_VERSINFO[1] >= 3) )); then + __bp_hook_preexec_into_ps0 + else + __bp_hook_preexec_into_debug + fi local existing_prompt_command # Remove setting our trap install string and sanitize the existing prompt command string @@ -392,7 +417,7 @@ __bp_install() { # Note: We need to add "trace" attribute to the function so that "trap # ... DEBUG" inside "__bp_install" takes an effect even when there was an # existing DEBUG trap. -declare -ft __bp_install +declare -ft __bp_install __bp_hook_preexec_into_debug # Sets an installation string as part of our PROMPT_COMMAND to install # after our session has started. This allows bash-preexec to be included diff --git a/test/bash-preexec.bats b/test/bash-preexec.bats index 83263f0..d325c95 100644 --- a/test/bash-preexec.bats +++ b/test/bash-preexec.bats @@ -94,8 +94,11 @@ set_exit_code_and_run_precmd() { bp_install trap_count_snapshot=$trap_invoked_count - [ "$(trap -p DEBUG | cut -d' ' -f3)" == "'__bp_preexec_invoke_exec" ] - [[ "${preexec_functions[*]}" == *"__bp_original_debug_trap"* ]] || return 1 + if (( BASH_VERSINFO[0] < 5 || (BASH_VERSINFO[0] == 5 && BASH_VERSINFO[1] < 3) )); then + # We override the DEBUG trap in Bash < 5.3 + [ "$(trap -p DEBUG | cut -d' ' -f3)" == "'__bp_preexec_invoke_exec" ] + [[ "${preexec_functions[*]}" == *"__bp_original_debug_trap"* ]] || return 1 + fi __bp_interactive_mode # triggers the DEBUG trap