From 127e2e5aa23a6adf2b257e492db5b75127ce1093 Mon Sep 17 00:00:00 2001 From: Alexander Roso Date: Thu, 7 May 2026 15:47:36 +0200 Subject: [PATCH] cdup: improvements --- plugins/cdup/cdup.plugin.zsh | 56 ++++++++++++++++++++++++++++++++---- zshrc | 4 +++ 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/plugins/cdup/cdup.plugin.zsh b/plugins/cdup/cdup.plugin.zsh index 4220071..5c131ae 100644 --- a/plugins/cdup/cdup.plugin.zsh +++ b/plugins/cdup/cdup.plugin.zsh @@ -1,20 +1,64 @@ +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 - cd $dir - return 0 + if [[ $closest ]]; then + echo $dir + return + else + match=$dir + break + fi fi done - if [[ $dir == "/" ]]; then return 1 - else _cdup ${dir:h} ${targets[@]} + if [[ $dir != "/" ]]; then + nextmatch=$(_cdup ${dir:h} ${targets[@]}) + match=${nextmatch:-$match} + fi + + if [[ $match ]]; then echo $match; return 0; + else return 1 fi } cdup() { - if [[ ${#@} -gt 0 ]]; then _cdup ${PWD:h} "$@" - else _cdup ${PWD:h} .git .hg package.json build.sbt + 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 diff --git a/zshrc b/zshrc index 0c1eb6d..1c2e813 100644 --- a/zshrc +++ b/zshrc @@ -128,6 +128,10 @@ if exists mail; then __chromaz_extra_left+=_prompt_cron_mails fi +if exists _prompt_cdup; then + __chromaz_extra_left+=_prompt_cdup +fi + tabs -4 #zprof