PROJECT_ROOT_INDICATORS=(.git .hg package.json build.sbt) # These commands find the topmost (i.e. shortest full path) project directory in # the hierarchy of the given directory. # cdup: changes to the match # _cdup: prints the match # _cdup_r: sets ~r as named dir for the match (set up as a chpwd hook) # # args: (cdup|_cdup) [-c] DIR [PROJECT_ROOT_INDICATOR...] # -c / --closest return the nearest project directory, i.e. least steps up, # possibly including the current directory # # DIR is starting point for the search # A PROJECT_ROOT_INDICATOR are files to look for to detect project roots. If # not given, a default list is used. $PROJECT_ROOT_INDICATORS can be used to # override the default globally _cdup() { zparseopts -D -E c=closest -closest=closest local dir=$1; shift local targets=("$@") local match nextmatch for target in $targets; do if [[ -e $dir/$target ]]; then if [[ $closest ]]; then echo $dir return else match=$dir break fi fi done if [[ $dir != "/" ]]; then nextmatch=$(_cdup ${dir:h} ${targets[@]}) match=${nextmatch:-$match} fi if [[ $match ]]; then echo $match; return 0; else return 1 fi } cdup() { zparseopts -D -E c=closest -closest=closest local target=$(_cdup $closest ${PWD:h} ${@:-$PROJECT_ROOT_INDICATORS}) if [[ $? != 0 ]]; then return 1; else cd $target fi } _cdup_r () { _cdup_project_root=$(_cdup ${PWD} ${PROJECT_ROOT_INDICATORS}) hash -d r=$_cdup_project_root } _prompt_cdup() { [[ -n $_cdup_project_root ]] && echo "project: ${_cdup_project_root:h:t}/${_cdup_project_root:t}" } autoload -U add-zsh-hook add-zsh-hook chpwd _cdup_r _cdup_r