Unverified Commit 840166f7 authored by Mark Vander Stel's avatar Mark Vander Stel
Browse files

Merge branch 'ismith/compatibility-with-bash-preexec'

PR/672
parents 4454faed bab7406c
......@@ -60,3 +60,10 @@ html_theme = 'sphinx_rtd_theme'
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
#html_static_path = ['_static']
# linkchecker dislikes anchor tags in github links: https://github.com/sphinx-doc/sphinx/issues/9016
# breezy-vcs.org has been having intermittent dns problems ("Temporary failure in name # resolution") for a while now
linkcheck_ignore = [
r'^https://github.com/rcaloras/bash-preexec/blob/master/README.md#install$',
r'^https://www.breezy-vcs.org/$'
]
......@@ -101,4 +101,14 @@ Adjust the path if you installed to a different location that the suggested
source Liquidprompt to avoid history and timing issues. Do not export
:envvar:`PROMPT_COMMAND`.
.. warning::
If you are using `bash-preexec <https://github.com/rcaloras/bash-preexec>`_, be
aware that bash-preexec **must** come **before** liquidprompt in your
``.bashrc``. This
contradicts their documentation, which says `"[bash-preexec] must be the last
thing imported in your bash profile"
<https://github.com/rcaloras/bash-preexec/blob/master/README.md#install>`_,
but since Liquid Prompt special-cases bash-preexec, it must be loaded after
bash-preexec.
Next up are the :doc:`config`.
......@@ -90,6 +90,24 @@ else
return
fi
__lp_use_bash_preexec() {
# If https://github.com/rcaloras/bash-preexec is present, we can (and should, because it interferes with
# PROMPT_COMMAND and DEBUG) use the zsh-hook like behavior it provides.
[[ "${__bp_imported-}" == "defined" ]]
}
__lp_array_contains() {
local target="$1"
shift
for element; do
if [[ $element == "$target" ]]; then
return 0
fi
done
return 1
}
###############
# OS specific #
###############
......@@ -3044,18 +3062,53 @@ prompt_on() {
declare -g +x PROMPT_COMMAND
fi
PROMPT_COMMAND=__lp_set_prompt
if (( LP_DEBUG_TIME )); then
PROMPT_COMMAND="time $PROMPT_COMMAND"
fi
if ! __lp_use_bash_preexec; then
PROMPT_COMMAND=__lp_set_prompt
if (( LP_ENABLE_RUNTIME || LP_ENABLE_RUNTIME_BELL || LP_ENABLE_TITLE_COMMAND )); then
_LP_AT_PROMPT=0
_LP_RUNTIME_LAST_SECONDS=$SECONDS
# __lp_before_command gets called just before bash executes a command,
# including $PROMPT_COMMAND
# Pass $_ to this call, because it sets $_ to what it already was
trap '__lp_before_command "$_"' DEBUG
if (( LP_DEBUG_TIME )); then
PROMPT_COMMAND="time $PROMPT_COMMAND"
fi
if (( LP_ENABLE_RUNTIME || LP_ENABLE_RUNTIME_BELL || LP_ENABLE_TITLE_COMMAND )); then
_LP_AT_PROMPT=0
_LP_RUNTIME_LAST_SECONDS=$SECONDS
# __lp_before_command gets called just before bash executes a command,
# including $PROMPT_COMMAND
# Pass $_ to this call, because it sets $_ to what it already was
trap '__lp_before_command "$_"' DEBUG
fi
else
# We do not want __lp_set_prompt to show up twice in precmd_functions; if it does, then LP_ENABLE_ERROR
# breaks because even if the first call of __lp_set_prompt has $? != 0, the second one will have $? == 0.
# (Same for __lp_debug_timed_lp_set_prompt.)
# This conditional is intended to check $precmd_functions for the presence of '__lp_set_prompt' or
# '__lp_debug_timed_lp_set_prompt' so they get added at most once
if ! ( __lp_array_contains __lp_set_prompt ${precmd_functions[@]+"${precmd_functions[@]}"} \
|| __lp_array_contains __lp_debug_timed_set_prompt ${precmd_functions[@]+"${precmd_functions[@]}"} );
then
if (( LP_DEBUG_TIME )); then
__lp_debug_timed_lp_set_prompt() {
time __lp_set_prompt
}
precmd_functions+=(__lp_debug_timed_lp_set_prompt)
else
precmd_functions+=(__lp_set_prompt)
fi
fi
if (( LP_ENABLE_RUNTIME || LP_ENABLE_RUNTIME_BELL )); then
_LP_RUNTIME_LAST_SECONDS=$SECONDS
# It's less bad to have this be duped than __lp_set_prompt, but let's be sure
if ! ( __lp_array_contains __lp_runtime_before ${preexec_functions[@]+"${preexec_functions[@]}"} ); then
preexec_functions+=(__lp_runtime_before)
fi
fi
if (( LP_ENABLE_TITLE_COMMAND )); then
# It's less bad to have this be duped than __lp_set_prompt, but let's be sure
if ! ( __lp_array_contains __lp_title_command ${preexec_functions[@]+"${preexec_functions[@]}"} ); then
preexec_functions+=(__lp_title_command)
fi
fi
fi
else # zsh
LP_OLD_PROMPT_COMMAND=""
......@@ -3096,12 +3149,31 @@ prompt_on() {
__lp_disable_hooks() {
if (( _LP_SHELL_bash )); then
PROMPT_COMMAND="${LP_OLD_PROMPT_COMMAND-}"
unset LP_OLD_PROMPT_COMMAND
if __lp_use_bash_preexec; then
# Disable previous hooks as options that set them
# may have changed
# (This is "remove the specified value(s) from the array", which bash does not make easy.)
local -a new_precmd_functions=()
for value in ${precmd_functions[@]+"${precmd_functions[@]}"}; do
[[ "$value" != "__lp_set_prompt" ]] && new_precmd_functions+=("$value")
done
precmd_functions=(${new_precmd_functions[@]+"${new_precmd_functions[@]}"})
# Now repeat for preexec (not precmd) functions
local -a new_preexec_functions=()
for value in ${preexec_functions[@]+"${preexec_functions[@]}"}; do
[[ "$value" != "__lp_runtime_before" ]] &&
[[ "$value" != "__lp_title_command" ]] && new_preexec_functions+=("$value")
done
preexec_functions=(${new_preexec_functions[@]+"${new_preexec_functions[@]}"})
else
PROMPT_COMMAND="${LP_OLD_PROMPT_COMMAND-}"
unset LP_OLD_PROMPT_COMMAND
# Disable the DEBUG trap used by the RUNTIME or TITLE_COMMAND features
if (( ${LP_ENABLE_RUNTIME-0} || ${LP_ENABLE_RUNTIME_BELL-0} || ${LP_ENABLE_TITLE_COMMAND-0} )); then
trap - DEBUG
# Disable the DEBUG trap used by the RUNTIME or TITLE_COMMAND features
if (( ${LP_ENABLE_RUNTIME-0} || ${LP_ENABLE_RUNTIME_BELL-0} || ${LP_ENABLE_TITLE_COMMAND-0} )); then
trap - DEBUG
fi
fi
else # zsh
# Disable previous hooks as options that set them
......
#!/bin/bash
# shellcheck disable=SC1090,SC1091,SC2031,SC2030
set -u
# Note: we do not call __lp_set_prompt directly in this file, as we do
# elsewhere; the idea is to check that it is properly integrated with
# bash-preexec.sh.
if [[ -z ${BASH_VERSION-} ]]; then
echo "$0 is irrelevant for non-bash shells."
exit 0
fi
# Install bash-preexec.sh
if [[ ! -f bash-preexec.sh ]]; then
echo "Installing bash-preexec.sh in $(pwd)..."
bash_preexec_version=0.4.1
curl -O https://raw.githubusercontent.com/rcaloras/bash-preexec/$bash_preexec_version/bash-preexec.sh
echo "Installed bash-preexec.sh in $(pwd)..."
fi
function setup_bash_preexec() {
set +u
source ./bash-preexec.sh
# bash-preexec doesn't install itself when sourced, it puts its install
# command into PROMPT_COMMAND. Call it here to finish setup.
__bp_install
set -u
}
function setup_liquidprompt() {
HOME=/home/user
PWD=$HOME
PS1="$ "
. ../liquidprompt --no-activate
# lp_theme activates liquid prompt a second time, which serves to double-check
# that we only add __lp_set_prompt to bash-preexec's precmd_functions _once_
LP_RUNTIME_ENABLED=1
LP_RUNTIME_THRESHOLD=1
LP_ENABLE_ERROR=1
LP_ENABLE_TITLE=1
lp_activate --no-config
lp_theme default
}
function setup() {
setup_bash_preexec
setup_liquidprompt
}
### Begin actual test functions. (Above this line are setup helpers.)
function test_bash_preexec_with_LP_RUNTIME {
(
setup
sleep 1
$PROMPT_COMMAND
assertTrue '[[ -n ${_LP_RUNTIME_SECONDS-} ]] && (( _LP_RUNTIME_SECONDS > 0 ))'
)
}
# Check it works with bash_preexec off
function test_no_bash_preexec_with_LP_RUNTIME {
(
setup_liquidprompt
sleep 1
$PROMPT_COMMAND
assertTrue '[[ -n ${_LP_RUNTIME_SECONDS-} ]] && (( _LP_RUNTIME_SECONDS > 0 ))'
)
}
function test_bash_preexec_with_LP_ERR {
(
setup
false # should get "1" in prompt
$PROMPT_COMMAND
assertContains $lp_error_color 1
)
}
# Check it works with bash_preexec off
function test_no_bash_preexec_with_LP_ERR {
(
setup_liquidprompt
false # should get "1" in prompt
$PROMPT_COMMAND
assertContains $lp_error_color 1
)
}
function test_bash_preexec_with_LP_ENABLE_TITLE {
(
setup
$PROMPT_COMMAND
assertNotNull "${_lp_generated_title-}"
)
}
# Check it works with bash_preexec off
function test_no_bash_preexec_with_LP_ENABLE_TITLE {
(
setup_liquidprompt
$PROMPT_COMMAND
assertNotNull "${_lp_generated_title-}"
)
}
function test_bash_preexec_with_prompt_off {
(
setup_bash_preexec
precmd_functions_size_before_liquidprompt="${#precmd_functions[@]}"
preexec_functions_size_before_liquidprompt="${#preexec_functions[@]}"
setup_liquidprompt
# We expect liquidprompt to add new entries to precmd_functions and
# preexec_functions, so the arrays should no longer be equal.
assertNotEquals "${#precmd_functions[@]}" "$precmd_functions_size_before_liquidprompt"
assertNotEquals "${#preexec_functions[@]}" "$preexec_functions_size_before_liquidprompt"
# This just checks that we did in fact get liquidprompt turned on.
false # should get "1" in prompt
$PROMPT_COMMAND
assertNotEquals "$PS1" "$ "
# Check that calling prompt_on twice doesn't insert duplicate copies of the
# hooks
precmd_functions_size_after_liquidprompt=${#precmd_functions[@]}
preexec_functions_size_after_liquidprompt=${#preexec_functions[@]}
prompt_on
assertEquals "${#precmd_functions[@]}" "$precmd_functions_size_after_liquidprompt"
assertEquals "${#preexec_functions[@]}" "$preexec_functions_size_after_liquidprompt"
# Here's the function we're actually here to test.
prompt_off
# With prompt off, it should just be back to plain old "$ "
false
$PROMPT_COMMAND
assertEquals "$PS1" "$ "
# And, having run prompt_off, precmd_functions and preexec_functions should
# be back to their original values.
assertEquals \
"$precmd_functions_size_before_liquidprompt" \
"${#precmd_functions[@]}"
assertEquals \
"$precmd_functions_size_before_liquidprompt" \
"${#preexec_functions[@]}"
)
}
. ./shunit2
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment