# 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 bare essentials. # # The secret sauce can be found at the bottom of this file, where the `chpwd` # hook function `_autoenv_chpwd` is added. # 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 # persistent. _autoenv_authorized() { local file=$1 # If autoenv cache directory does not exist, create it. local cache_dir=~/.cache/autoenv ! [ -d $cache_dir ] && mkdir -p $cache_dir local authorized_file=$cache_dir/authorized # Define a map to hold authorized key value pairs. typeset -A authorized=() # If the authorized file exists, load it into the map. [ -f $authorized_file ] && typeset -A authorized=(`cat $authorized_file`) # If the given file has been authorized, i.e. the modified time matches that # held in the authorized file, 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 all directories containing a .enter file by searching up the directory # tree starting in the current directory. _autoenv_find_enter_directories() { 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 an enter script is found in the current directory, return it. [ -f $next/.enter ] && echo $next # If the current directory equals the next directory we are done, otherwise # update the current directory. [[ $current == $next ]] && return || local current=$next 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 reversed entered directory array. for entered in ${(aO)_autoenv_entered}; do # If the the current directory was previously entered then exit. ! [[ $PWD/ == $entered/* ]] && _autoenv_exit $entered done # Find all enter script directories, store them in an array. local enter_dirs=(`_autoenv_find_enter_directories`) # Loop over reversed enter script directories array, so enter scripts found # last are sourced first, then source all enter scripts. for enter in ${(aO)enter_dirs}; do _autoenv_enter $enter; done } # 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