Skip to content
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

Support the array PROMPT_COMMAND (bash >= 5.1) #141

Merged
merged 1 commit into from
Mar 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions bash-preexec.sh
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,8 @@ __bp_set_ret_value() {

__bp_in_prompt_command() {

local prompt_command_array
IFS=$'\n;' read -rd '' -a prompt_command_array <<< "${PROMPT_COMMAND:-}"
local prompt_command_array IFS=$'\n;'
read -rd '' -a prompt_command_array <<< "${PROMPT_COMMAND[*]:-}"

local trimmed_arg
__bp_trim_whitespace trimmed_arg "${1:-}"
Expand Down Expand Up @@ -290,7 +290,7 @@ __bp_preexec_invoke_exec() {

__bp_install() {
# Exit if we already have this installed.
if [[ "${PROMPT_COMMAND:-}" == *"__bp_precmd_invoke_cmd"* ]]; then
if [[ "${PROMPT_COMMAND[*]:-}" == *"__bp_precmd_invoke_cmd"* ]]; then
return 1;
fi

Expand Down Expand Up @@ -331,14 +331,20 @@ __bp_install() {
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"
if [[ "${existing_prompt_command:-:}" == ":" ]]; then
existing_prompt_command=
fi

# Install our hooks in PROMPT_COMMAND to allow our trap to know when we've
# actually entered something.
PROMPT_COMMAND=$'__bp_precmd_invoke_cmd\n'
if [[ "${existing_prompt_command:-:}" != ":" ]]; then
PROMPT_COMMAND+=${existing_prompt_command}$'\n'
fi;
PROMPT_COMMAND+='__bp_interactive_mode'
PROMPT_COMMAND='__bp_precmd_invoke_cmd'
PROMPT_COMMAND+=${existing_prompt_command:+$'\n'$existing_prompt_command}
if (( BASH_VERSINFO[0] > 5 || (BASH_VERSINFO[0] == 5 && BASH_VERSINFO[1] >= 1) )); then
PROMPT_COMMAND+=('__bp_interactive_mode')
else
# shellcheck disable=SC2179 # PROMPT_COMMAND is not an array in bash <= 5.0
PROMPT_COMMAND+=$'\n__bp_interactive_mode'
akinomyoga marked this conversation as resolved.
Show resolved Hide resolved
fi

# Add two functions to our arrays for convenience
# of definition.
Expand All @@ -361,8 +367,10 @@ __bp_install_after_session_init() {
local sanitized_prompt_command
__bp_sanitize_string sanitized_prompt_command "${PROMPT_COMMAND:-}"
if [[ -n "$sanitized_prompt_command" ]]; then
# shellcheck disable=SC2178 # PROMPT_COMMAND is not an array in bash <= 5.0
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}
}

Expand Down
32 changes: 23 additions & 9 deletions test/bash-preexec.bats
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,23 @@ setup() {
source "${BATS_TEST_DIRNAME}/../bash-preexec.sh"
}

# Evaluates all the elements of PROMPT_COMMAND
eval_PROMPT_COMMAND() {
local prompt_command
for prompt_command in "${PROMPT_COMMAND[@]}"; do
eval "$prompt_command"
done
}

# Joins the elements of PROMPT_COMMAND with $'\n'
join_PROMPT_COMMAND() {
local IFS=$'\n'
echo "${PROMPT_COMMAND[*]}"
}

bp_install() {
__bp_install_after_session_init
eval "$PROMPT_COMMAND"
eval_PROMPT_COMMAND
}

test_echo() {
Expand Down Expand Up @@ -63,7 +77,7 @@ set_exit_code_and_run_precmd() {
[[ "$PROMPT_COMMAND" == *"trap - DEBUG"* ]] || return 1
[[ "$PROMPT_COMMAND" == *"__bp_install"* ]] || return 1

eval "$PROMPT_COMMAND"
eval_PROMPT_COMMAND

[[ "$PROMPT_COMMAND" != *"trap DEBUG"* ]] || return 1
[[ "$PROMPT_COMMAND" != *"__bp_install"* ]] || return 1
Expand Down Expand Up @@ -106,7 +120,7 @@ set_exit_code_and_run_precmd() {
bp_install

PROMPT_COMMAND="$PROMPT_COMMAND; true"
eval "$PROMPT_COMMAND"
eval_PROMPT_COMMAND
}

@test "Appending or prepending to PROMPT_COMMAND should work after bp_install_after_session_init" {
Expand All @@ -119,7 +133,7 @@ set_exit_code_and_run_precmd() {
PROMPT_COMMAND="true; $PROMPT_COMMAND"
PROMPT_COMMAND="true; $PROMPT_COMMAND"
PROMPT_COMMAND="true $nl $PROMPT_COMMAND"
eval "$PROMPT_COMMAND"
eval_PROMPT_COMMAND
}

# Case where a user is appending or prepending to PROMPT_COMMAND.
Expand All @@ -132,21 +146,21 @@ set_exit_code_and_run_precmd() {
PROMPT_COMMAND="$PROMPT_COMMAND"$'\n echo after'
PROMPT_COMMAND="echo after2; $PROMPT_COMMAND;"

eval "$PROMPT_COMMAND"
eval_PROMPT_COMMAND

expected_result=$'__bp_precmd_invoke_cmd\necho after2; echo before; echo before2\n echo after\n__bp_interactive_mode'
[ "$PROMPT_COMMAND" == "$expected_result" ]
[ "$(join_PROMPT_COMMAND)" == "$expected_result" ]
}

@test "Adding to PROMPT_COMMAND after with semicolon" {
PROMPT_COMMAND="echo before"
__bp_install_after_session_init
PROMPT_COMMAND="$PROMPT_COMMAND; echo after"

eval "$PROMPT_COMMAND"
eval_PROMPT_COMMAND

expected_result=$'__bp_precmd_invoke_cmd\necho before\n echo after\n__bp_interactive_mode'
[ "$PROMPT_COMMAND" == "$expected_result" ]
[ "$(join_PROMPT_COMMAND)" == "$expected_result" ]
}

@test "during install PROMPT_COMMAND and precmd functions should be executed each once" {
Expand All @@ -157,7 +171,7 @@ set_exit_code_and_run_precmd() {
PROMPT_COMMAND="echo after2; $PROMPT_COMMAND;"

precmd() { echo "inside precmd"; }
run eval "$PROMPT_COMMAND"
run eval_PROMPT_COMMAND
[ "${lines[0]}" == "after2" ]
[ "${lines[1]}" == "before" ]
[ "${lines[2]}" == "before2" ]
Expand Down