-
Notifications
You must be signed in to change notification settings - Fork 97
Request for public/stable APIs to enable/disable the hooks and to manually invoke registered functions #129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -71,7 +71,11 @@ __bp_inside_precmd=0 | |
__bp_inside_preexec=0 | ||
|
||
# Initial PROMPT_COMMAND string that is removed from PROMPT_COMMAND post __bp_install | ||
__bp_install_string=$'__bp_trap_string="$(trap -p DEBUG)"\ntrap - DEBUG\n__bp_install' | ||
bash_preexec_install_string=$'__bp_trap_string="$(trap -p DEBUG)"\ntrap - DEBUG\n__bp_install' | ||
|
||
# The command string that is registered to the DEBUG trap. | ||
# shellcheck disable=SC2016 | ||
bash_preexec_trapdebug_string='__bp_preexec_invoke_exec "$_"' | ||
|
||
# Fails if any of the given variables are readonly | ||
# Reference https://stackoverflow.com/a/4441178 | ||
|
@@ -157,21 +161,38 @@ __bp_precmd_invoke_cmd() { | |
return | ||
fi | ||
local __bp_inside_precmd=1 | ||
bash_preexec_invoke_precmd_functions "$__bp_last_ret_value" "$__bp_last_argument_prev_command" | ||
|
||
__bp_set_ret_value "$__bp_last_ret_value" "$__bp_last_argument_prev_command" | ||
} | ||
|
||
# This function invokes every function defined in our function array | ||
# "precmd_function". This function receives the arguments $1 and $2 for $? and | ||
# $_, respectively, which will be set for each precmd function. This function | ||
# returns the last non-zero exit status of the hook functions. If there is no | ||
# error, this function returns 0. | ||
bash_preexec_invoke_precmd_functions() { | ||
local lastexit=$1 lastarg=$2 | ||
# Invoke every function defined in our function array. | ||
local precmd_function | ||
local precmd_function_ret_value | ||
local precmd_ret_value=0 | ||
for precmd_function in "${precmd_functions[@]}"; do | ||
|
||
# Only execute this function if it actually exists. | ||
# Test existence of functions with: declare -[Ff] | ||
if type -t "$precmd_function" 1>/dev/null; then | ||
__bp_set_ret_value "$__bp_last_ret_value" "$__bp_last_argument_prev_command" | ||
__bp_set_ret_value "$lastexit" "$lastarg" | ||
# Quote our function invocation to prevent issues with IFS | ||
"$precmd_function" | ||
precmd_function_ret_value=$? | ||
if [[ "$precmd_function_ret_value" != 0 ]]; then | ||
precmd_ret_value="$precmd_function_ret_value" | ||
fi | ||
fi | ||
done | ||
|
||
__bp_set_ret_value "$__bp_last_ret_value" | ||
__bp_set_ret_value "$precmd_ret_value" | ||
} | ||
|
||
# Sets a return value in $?. We may want to get access to the $? variable in our | ||
|
@@ -260,7 +281,27 @@ __bp_preexec_invoke_exec() { | |
return | ||
fi | ||
|
||
# Invoke every function defined in our function array. | ||
bash_preexec_invoke_preexec_functions "${__bp_last_ret_value:-}" "$__bp_last_argument_prev_command" "$this_command" | ||
local preexec_ret_value=$? | ||
|
||
# Restore the last argument of the last executed command, and set the return | ||
# value of the DEBUG trap to be the return code of the last preexec function | ||
# to return an error. | ||
# If `extdebug` is enabled a non-zero return value from any preexec function | ||
# will cause the user's command not to execute. | ||
# Run `shopt -s extdebug` to enable | ||
__bp_set_ret_value "$preexec_ret_value" "$__bp_last_argument_prev_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 | ||
# argument $3 specifies the user command that is going to be executed | ||
# (corresponding to BASH_COMMAND in the DEBUG trap). This function returns the | ||
# last non-zero exit status from the preexec functions. If there is no error, | ||
# this function returns `0`. | ||
bash_preexec_invoke_preexec_functions() { | ||
local lastexit=$1 lastarg=$2 this_command=$3 | ||
local preexec_function | ||
local preexec_function_ret_value | ||
local preexec_ret_value=0 | ||
|
@@ -269,7 +310,7 @@ __bp_preexec_invoke_exec() { | |
# Only execute each function if it actually exists. | ||
# Test existence of function with: declare -[fF] | ||
if type -t "$preexec_function" 1>/dev/null; then | ||
__bp_set_ret_value "${__bp_last_ret_value:-}" | ||
__bp_set_ret_value "$lastexit" "$lastarg" | ||
akinomyoga marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# Quote our function invocation to prevent issues with IFS | ||
"$preexec_function" "$this_command" | ||
preexec_function_ret_value="$?" | ||
|
@@ -278,14 +319,7 @@ __bp_preexec_invoke_exec() { | |
fi | ||
fi | ||
done | ||
|
||
# Restore the last argument of the last executed command, and set the return | ||
# value of the DEBUG trap to be the return code of the last preexec function | ||
# to return an error. | ||
# If `extdebug` is enabled a non-zero return value from any preexec function | ||
# will cause the user's command not to execute. | ||
# Run `shopt -s extdebug` to enable | ||
__bp_set_ret_value "$preexec_ret_value" "$__bp_last_argument_prev_command" | ||
__bp_set_ret_value "$preexec_ret_value" | ||
} | ||
|
||
__bp_install() { | ||
|
@@ -294,7 +328,8 @@ __bp_install() { | |
return 1 | ||
fi | ||
|
||
trap '__bp_preexec_invoke_exec "$_"' DEBUG | ||
# shellcheck disable=SC2064 | ||
trap "$bash_preexec_trapdebug_string" DEBUG | ||
|
||
# Preserve any prior DEBUG trap as a preexec function | ||
local prior_trap | ||
|
@@ -327,7 +362,7 @@ __bp_install() { | |
# Remove setting our trap install string and sanitize the existing prompt command string | ||
existing_prompt_command="${PROMPT_COMMAND:-}" | ||
# Edge case of appending to PROMPT_COMMAND | ||
existing_prompt_command="${existing_prompt_command//$__bp_install_string/:}" # no-op | ||
existing_prompt_command="${existing_prompt_command//$bash_preexec_install_string/:}" # no-op | ||
existing_prompt_command="${existing_prompt_command//$'\n':$'\n'/$'\n'}" # remove known-token only | ||
existing_prompt_command="${existing_prompt_command//$'\n':;/$'\n'}" # remove known-token only | ||
__bp_sanitize_string existing_prompt_command "$existing_prompt_command" | ||
|
@@ -346,10 +381,13 @@ __bp_install() { | |
PROMPT_COMMAND+=$'\n__bp_interactive_mode' | ||
fi | ||
|
||
# Add two functions to our arrays for convenience | ||
# of definition. | ||
precmd_functions+=(precmd) | ||
preexec_functions+=(preexec) | ||
# Add two functions to our arrays for convenience of definition only when | ||
# the functions have not yet added. | ||
if [[ ! ${__bp_installed_convenience_functions-} ]]; then | ||
akinomyoga marked this conversation as resolved.
Show resolved
Hide resolved
|
||
__bp_installed_convenience_functions=1 | ||
precmd_functions+=(precmd) | ||
preexec_functions+=(preexec) | ||
fi | ||
|
||
# Invoke our two functions manually that were added to $PROMPT_COMMAND | ||
__bp_precmd_invoke_cmd | ||
|
@@ -371,8 +409,46 @@ __bp_install_after_session_init() { | |
PROMPT_COMMAND=${sanitized_prompt_command}$'\n' | ||
fi | ||
# shellcheck disable=SC2179 # PROMPT_COMMAND is not an array in bash <= 5.0 | ||
PROMPT_COMMAND+=${__bp_install_string} | ||
PROMPT_COMMAND+=${bash_preexec_install_string} | ||
} | ||
|
||
# Remove hooks installed in the DEBUG trap and PROMPT_COMMAND. | ||
bash_preexec_uninstall() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not convinced that bash-preexec should be responsible for maintaining any over head of uninstalling itself from both trap and prompt_command. Any libraries using these shared variables have more or less had to clean them up and maintain them on their own, as does bash-preexec with its installation. With the defined global variables what's stopping from just implementing this in your own library? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
If the setup of However, if the This is actually the reason that I would like to request the "stable" public API rather than relying on the details of the internal implementation that can be frequently changed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I get your reasoning and desire for this as a way to help with your library and not just implementing it yourself. I just think there's no real standard here I've seen other libraries that have clashed with bash-preexec as well since they also make the assumption they'll have access to these parts of the system configuration. (Liquid Prompt is one example) My assumption is, these too can cause issues with ble.sh and we're trying to chase individual fires here. I am concerned that this is an esoteric use case and will likely just add operational overhead to maintaining it. With that said, if any other contributors see value in this I'm supportive. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks. Maybe I miss your exact point (What does "the system configuration" mean?), but I think I'll later need to look at Liquid Prompt. |
||
# Remove __bp_install hook from PROMPT_COMMAND | ||
# shellcheck disable=SC2178 # PROMPT_COMMAND is not an array in bash <= 5.0 | ||
if [[ ${PROMPT_COMMAND-} == *"$bash_preexec_install_string"* ]]; then | ||
PROMPT_COMMAND="${PROMPT_COMMAND//${bash_preexec_install_string}[;$'\n']}" # Edge case of appending to PROMPT_COMMAND | ||
PROMPT_COMMAND="${PROMPT_COMMAND//$bash_preexec_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_precmd_invoke_cmd | __bp_interactive_mode) | ||
prompt_command= ;; | ||
*) | ||
prompt_command=${prompt_command/#$'__bp_precmd_invoke_cmd\n'/$'\n'} | ||
prompt_command=${prompt_command%$'\n__bp_interactive_mode'} | ||
prompt_command=${prompt_command#$'\n'} | ||
esac | ||
PROMPT_COMMAND[i]=$prompt_command | ||
done | ||
|
||
# Remove preexec hook in the DEBUG trap | ||
local q="'" Q="'\''" | ||
if [[ $(trap -p DEBUG) == "trap -- '${bash_preexec_trapdebug_string//$q/$Q}' DEBUG" ]]; then | ||
if [[ ${__bp_trap_string-} ]]; then | ||
eval -- "$__bp_trap_string" | ||
else | ||
trap - DEBUG | ||
fi | ||
fi | ||
} | ||
# Note: We need to add "trace" attribute to the function so that "trap - DEBUG" | ||
# inside the function takes an effect. | ||
declare -ft bash_preexec_uninstall | ||
akinomyoga marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# Run our install so long as we're not delaying it. | ||
if [[ -z "${__bp_delay_install:-}" ]]; then | ||
|
Uh oh!
There was an error while loading. Please reload this page.