Bruno BELANYI
2e927c89e7
It seems like the idiomatic way to update $PROMPT_COMMAND is to use variable expansion to add a semi-colon and a space before the command we're adding. I also switched from prepending my commands to appending them, which allows overriding behaviour, such as terminal titles which could be set from system files.
118 lines
4.1 KiB
Plaintext
Executable file
118 lines
4.1 KiB
Plaintext
Executable file
# This script applies local configuration changes from the start of your
|
|
# file hierarchy tree down to your current working directory.
|
|
#
|
|
# When you change dirctories it automatically undoes those changes by using
|
|
# the command contained in the associative array `__undo_commands` starting by
|
|
# the ones furthest down until the common ancestor with your current
|
|
#
|
|
# The '.localrc' files should add an undo command to __undo_commands which is
|
|
# keyed with the '__UNDO_DIR' variable (i.e: __undo_commands[$__UNDO_DIR]='...')
|
|
# This variable will be eval-ed to undo your local changes.
|
|
#
|
|
# Example 1: a project that needs to have the PATH pre-pended
|
|
#
|
|
# # Taking advantage of PATH being expanded when sourcing the file
|
|
# __undo_commands[$__UNDO_DIR]="export PATH='$PATH'"
|
|
# export PATH="$__UNDO_DIR/bin:$PATH"
|
|
#
|
|
# Example 2: a project that needs to activate a virtualenv
|
|
#
|
|
# __undo_commands[$__UNDO_DIR]='deactivate'
|
|
# source env/bin/activate
|
|
|
|
# Contains the commands to undo the changes made in a directory
|
|
declare -A __undo_commands
|
|
# Contains the PWD of the previous command (and not $OLDPWD)
|
|
__LAST_PWD='/'
|
|
# Declare this variable to print some debug information
|
|
#DEBUG_LOCALRC=toto
|
|
|
|
# Source localrc files from "$1" and its parents unless we find "$2" and stop
|
|
function __source_localrc_files_rec() {
|
|
# "$1" and "$2" should not have any trailing slashes unless they are '/'
|
|
if [ "$1" != "$2" ]; then
|
|
# FIXME: condition should be unnecessary, but is there to avoid loops
|
|
[ "$1" != '/' ] && __source_localrc_files_rec "$(dirname "$1")" "$2"
|
|
|
|
# Export the special '__UNDO_DIR' variable to key into '__undo_commands'
|
|
export __UNDO_DIR="$1"
|
|
local localrc="$1/.localrc"
|
|
# The post-fix traversal sourced the parent before the child
|
|
if [ -r "$localrc" ]; then
|
|
source "$localrc"
|
|
|
|
if [ -n "${DEBUG_LOCALRC+set}" ]; then
|
|
echo "sourced $localrc with __UNDO_DIR as '$__UNDO_DIR'"
|
|
fi
|
|
fi
|
|
unset -v __UNDO_DIR
|
|
fi
|
|
}
|
|
|
|
# Undo the changes made by "$1" and its parents unless we find "$2" and stop
|
|
function __undo_localrc_changes() {
|
|
# Undo the changes for our parent directory if we aren't at the common root
|
|
if [ "$1" != "$2" ]; then
|
|
# If there is a command to undo the changes for that directory, do it
|
|
[ -n "${DEBUG_LOCALRC+set}" ] && echo "Looking at undoing $1"
|
|
if [ -n "${__undo_commands[$1]+set}" ]; then
|
|
eval "${__undo_commands[$1]}"
|
|
|
|
[ -n "${DEBUG_LOCALRC+set}" ] && echo "undid $1/.localrc"
|
|
fi
|
|
|
|
# FIXME: condition should be unnecessary, but is there to avoid loops
|
|
[ "$1" != '/' ] && __undo_localrc_changes "$(dirname "$1")" "$2"
|
|
fi
|
|
}
|
|
|
|
# Return the closest common parent directory of "$1" and "$2"
|
|
function common_parent() {
|
|
local directories=("$1")
|
|
|
|
while [ "${directories[-1]}" != '/' ]; do
|
|
directories+=("$(dirname "${directories[-1]}")")
|
|
done
|
|
|
|
for candidate in "${directories[@]}"; do
|
|
case "$2" in
|
|
"$candidate"*) printf "%s" "$candidate"; break;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
function __source_localrc_files() {
|
|
# Only do it if we changed our directory since the last command
|
|
if [ "$__LAST_PWD" = "$PWD" ]; then
|
|
return 0
|
|
fi
|
|
|
|
# Find the closest common parent directory
|
|
local parent='/'
|
|
if [ -n "$__LAST_PWD" ]; then
|
|
parent=$(common_parent "$__LAST_PWD" "$PWD")
|
|
fi
|
|
|
|
if [ -n "${DEBUG_LOCALRC+set}" ]; then
|
|
echo "DEBUG"
|
|
echo "LAST: $__LAST_PWD"
|
|
echo "CUR: $PWD"
|
|
echo "PARENT: $parent"
|
|
fi
|
|
|
|
__undo_localrc_changes "$__LAST_PWD" "$parent"
|
|
__source_localrc_files_rec "$PWD" "$parent"
|
|
|
|
# Update our last seen working directory
|
|
__LAST_PWD="$PWD"
|
|
}
|
|
|
|
# Execute this command every time
|
|
if [ -n "$BASH_VERSION" ]; then
|
|
[ -n "${DEBUG_LOCALRC+set}" ] && echo "Loaded Bash"
|
|
PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND; }__source_localrc_files"
|
|
elif [ -n "$ZSH_VERSION" ]; then
|
|
[ -n "${DEBUG_LOCALRC+set}" ] && echo "Loaded Zsh"
|
|
precmd_functions+=( __source_localrc_files)
|
|
fi
|