# Shamelessly based on http://glandium.org/blog/?p=170
#
-__git_get_repo_root()
+__git_get_reporoot()
{
+ # return the full path to the root of the current git repository
local relroot
relroot="$(git rev-parse --show-cdup 2>/dev/null)" || return 1
if [ -n "$relroot" ]; then
__git_get_branch()
{
+ # return the name of the git branch we're on
local ref
ref=$(git symbolic-ref -q HEAD 2>/dev/null \
- || git-name-rev --name-only HEAD 2>/dev/null)
+ || git-name-rev --name-only HEAD 2>/dev/null) || return 1
echo "${ref#refs/heads/}"
}
-__get_root_offsets()
+__vcs_get_repo_type()
{
- local pwda reporoot loc
- pwda=(${(s:/:)PWD})
- reporoot=(${(s:/:)1})
- echo $((1 - $#reporoot)) $(($#pwda - $#reporoot))
+ # return the type of the closest repository in the path hierarchy
+ local dir
+ while true; do
+ [ -d ${dir}.git ] && echo git && break
+ [ -d ${dir}.bzr ] && echo bzr && break
+ [ -d ${dir}.hg ] && echo hg && break
+ [ -d ${dir}.svn ] && echo svn && break
+ [ -d ${dir}.svk ] && echo svk && break
+ [ -d ${dir}CVS ] && echo cvs && break
+ [ "$(readlink -f ${dir:-.})" = / ] && echo NONE && break
+ dir="../$dir"
+ done
}
-__get_prompt_path_components()
+__vcs_get_prompt_path_components()
{
- local reporoot
- reporoot="$1"
+ # return formatted path components (prefix branch postfix) given
+ # the repository root and the branch.
- set -- $(__get_root_offsets "$reporoot")
- if [ "$2" -le 0 ]; then
- echo %~
- else
- echo "%${1}~" "%${2}~"
+ # shortcut: if there are no arguments, return a default prompt
+ if [ -z "${1:-}" ]; then
+ pwdnamed="%${_PROMPT_PATH_MAXLEN}<..<%~%<<"
+ pwdnamed="${(%)pwdnamed}"
+ echo "$pwdnamed"
+ return
fi
-}
-__vcs_get_repo_type()
-{
- while true; do
- [ -d .git ] && echo git && break
- [ -d .bzr ] && echo bzr && break
- [ -d .hg ] && echo hg && break
- [ -d .svn ] && echo svn && break
- [ -d .svk ] && echo svk && break
- [ -d CVS ] && echo cvs && break
- [ "$PWD" = / ] && echo NONE && return 1
- cd ..
- done
+ local reporoot branch
+ reporoot="${1%%/}"
+ branch="$2"
+
+ # replace named directories in the PWD, we need thi for the proper component
+ # count later
+ local pwdnamed="%~"
+ pwdnamed="${(%)pwdnamed}"
+
+ # store paths in arrays for component count calculation
+ typeset -la apwd apwdnamed areporoot
+ apwd=(${(s:/:)PWD})
+ apwdnamed=(${(s:/:)pwdnamed})
+ areporoot=(${(s:/:)reporoot})
+
+ # get the number of leading and trailing path components. Since we're using
+ # %~ later and then /home/madduck suddenly becomes ~, which is 1, not
+ # 2 components, we calculate the leading component count by using the named
+ # path and the number of post components
+ local precomps postcomps
+ postcomps=$(($#apwd - $#areporoot))
+ precomps=$(($#apwdnamed - $postcomps))
+
+ local postfix
+ if (( $postcomps > 0 )); then
+ postfix="%${postcomps}~"
+ postfix="${(%)postfix}"
+ fi
+
+ # we don't want the prompt to get too long, so keep the total prompt length
+ # under $_PROMPT_PATH_MAXLEN (25), but ensure that the prefix is not shorter
+ # than $_PROMPT_PATH_MINLEN (10), no matter what
+ local prelen minlen prefix
+ prelen=$((${_PROMPT_PATH_MAXLEN:-25} - $#branch - $#postfix))
+ minlen=${_PROMPT_PATH_MINLEN:-10}
+ (( $prelen < $minlen )) && prelen=$minlen
+ prefix="%${prelen}<..<%-${precomps}~%<<"
+ prefix="${(%)prefix}"
+
+ echo "$prefix" "$branch" "$postfix"
}
__vcs_set_prompt_variables()
{
- local pre branch post
- local MAXLEN=25
- local repotype="${1:-$(__vcs_get_repo_type)}"
+ # set psvar[1..3] depending on repo type, or just psvar[1] if no repo found
+ local reporoot branch repotype
+ repotype="${1:-$(__vcs_get_repo_type)}"
case "$repotype" in
git)
- local reporoot="$(__git_get_repo_root)"
- set -- $(__get_prompt_path_components "$reporoot")
- branch="$(__git_get_branch)"
- post="${(%)2}"
- local prelen="$((MAXLEN - $#post - $#branch))"
- [ $prelen -lt 10 ] && prelen=10
- pre="%${prelen}<..<${1}%<<"
- pre="${(%)pre}"
+ reporoot="$(__git_get_reporoot)" ||
+ { error "could not determine git repository root"; return 1 }
+ branch="$(__git_get_branch)" ||
+ { error "could not determine git branch"; return 1 }
;;
*)
case "$repotype" in
return
esac
- psvar[1]="$pre"
- psvar[2]="$branch"
- psvar[3]="$post"
+ set -- $(__vcs_get_prompt_path_components "$reporoot" "$branch")
+ psvar[1]="$1"
+ psvar[2]="$2"
+ psvar[3]="$3"
}
if ! is_root; then
local vcs="$(__vcs_get_repo_type)"
case "$(history $(($HISTCMD - 1)))" in
# $vcs appeared in last command, so be sure to update
- *${vcs}*) __vcs_set_prompt_variables
+ *${vcs}*) __vcs_set_prompt_variables "$vcs"
esac
}
precmd_functions+=_update_vcs_prompt_vars_if_vcs_ran