diff --git a/autoenv/autoenv.plugin.zsh b/autoenv/autoenv.plugin.zsh new file mode 100644 index 0000000..c47c1bc --- /dev/null +++ b/autoenv/autoenv.plugin.zsh @@ -0,0 +1,104 @@ +# Automatically update the environment when the current working directory +# changes, this is a reimplementation of the ideas found in the repository +# https://github.com/Tarrasch/zsh-autoenv stripped down to suit my specific +# needs. + +# Global entered directories array. +_autoenv_entered=() + +# Check if the given file is authorized, if not prompt the user to authorize, +# ignore, or view the file. Authorized files and their modified times are +# stored in the ~/.cache/autoenv/authorized file to make authorization +# persistant. +_autoenv_authorized() { + local file=$1 + # If autoenv cache directory does not exist, create it. + local cache_dir=~/.config/autoenv + ! [ -d $cache_dir ] && mkdir -p $cache_dir + local authorized_file=$cache_dir/authorized + # Define the associative array to hold authorized key value pairs. + # If the authorized file exists, load it into an associative array. + typeset -A authorized=() + [ -f $authorized_file ] && typeset -A authorized=(`cat $authorized_file`) + # If the given file has been authorized, return. + local modified_time=`zstat +mtime $file` + [ "$authorized[$file]" = "$modified_time" ] && return + # Prompt to authorize file. + while true; do + read "answer?Authorize $file [Y/n/v]? " + case "$answer" in + y|Y|yes|'') # Authorize the file. + authorized[$file]=$modified_time; break ;; + n|N|no) return 1 ;; # Do not authorize the file. + v|V|view) cat $file ;; # View the file. + esac + done + # Store authorized associative array in authorized file. + echo ${(kv)authorized} > $authorized_file +} + +# Source an enter script and add its directory to the global entered +# directories array. +_autoenv_enter() { + local entered=$1 + # If entered exists in the entered directories array, return. + (( ${+_autoenv_entered[${_autoenv_entered[(i)$entered]}]} )) && return + # If the enter script is not authorized, return. + _autoenv_authorized $entered/.enter || return + # Source the enter script. + source $entered/.enter + # Add the entered directory to the global entered array. + _autoenv_entered+=$entered +} + +# Source an exit script and remove its directory from the global entered +# directories array. +_autoenv_exit() { + local entered=$1 + # If the exit script is not authorized, return. + _autoenv_authorized $entered/.exit || return + # Source the exit script. + source $entered/.exit + # Remove the entered directory from the global entered array. + _autoenv_entered[${_autoenv_entered[(i)$entered]}]=() +} + +# Find a directory containing a .enter file by searching up the directory tree +# starting in the current directory. +_autoenv_find_enter() { + local current=$PWD + # If an enter script is found in the current directory, return it. + [ -f "$current/.enter" ] && echo $current + # Loop until an enter script or the root directory is found. + while true; do + # Go up one directory and make the path absolute. + local next=$current/..; local next=${next:A} + # If the current directory equals the next directory, return. + [[ $current == $next ]] && return || local current=$next + # If an enter script is found in the current directory, return it. + [ -f $current/.enter ] && echo $current + done +} + +# A chpwd hook function which automatically sources enter and exit scripts to +# setup local environments for directory and its subdirectories. +_autoenv_chpwd() { + local entered + # Loop over the entered directory stack. + for entered in $_autoenv_entered; do + # If the the current directory was previously entered then exit. + # TODO: Verify what this condition expression actually does. + ! [[ $PWD/ == $entered/* ]] && _autoenv_exit $entered + done + # Find the nearest enter script directory. + local enter=`_autoenv_find_enter` + # If the enter directory exists, enter it. + [ -d "$enter" ] && _autoenv_enter $enter +} + +# Register the autoenv chpwd hook. +autoload -U add-zsh-hook +add-zsh-hook chpwd _autoenv_chpwd + +# Ensure autoenv is activated in the current directory on first load. +_autoenv_chpwd diff --git a/zshrc b/zshrc index 48cbe52..7bfd75c 100644 --- a/zshrc +++ b/zshrc @@ -12,6 +12,7 @@ source-plugin() { source-plugin zsh-autosuggestions source-plugin zsh-history-substring-search source-plugin zsh-syntax-highlighting +source-plugin autoenv # Disable non end-of-line autosuggest accept widgets ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=(end-of-line vi-end-of-line)