Skip to content

Commit

Permalink
Support the array PROMPT_COMMAND in Bash 5.1+
Browse files Browse the repository at this point in the history
  • Loading branch information
akinomyoga committed Mar 7, 2023
1 parent 77aec5f commit 219ae02
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 17 deletions.
21 changes: 13 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 @@ -332,11 +332,14 @@ __bp_install() {

# 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 [[ -n "$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'
fi

# Add two functions to our arrays for convenience
# of definition.
Expand All @@ -359,8 +362,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

0 comments on commit 219ae02

Please sign in to comment.