# 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