+# Checks if the command provided is in the commands list and is
+# executable
+check_command(){
+ [[ -n ${commands[$1]} ]] && [ -x ${commands[$1]} ] && return 0
+ return 1
+}
+
+# If name should be overwritten (eg for git-svn), do it.
+vcs_adjust(){
+ [[ -n ${vcs_comm[overwrite_name]} ]] && vcs=${vcs_comm[overwrite_name]}
+ return 0
+}
+
+# Formats two VCS_info messages, one with colors, and one without
+vcs_formats(){
+ local action=$1 branch=$2 base=$3 rev=$4
+ local msg
+ local -i i
+
+ # printf is for readability (it's easier to find %s)
+ msg="(%s)${MINUS_CHAR}[%s/%s"
+ msg=$(printf $msg $vcs ${base/*\/} $branch)
+
+ # If there is a revnumber, print it
+ if [ ! -z ${rev} ]; then
+ msg="${msg}:%s"
+ msg=$(printf $msg $rev)
+ fi
+
+ # Print the current cvs action state
+ if [ ! -z ${action} ] ; then
+ msg="${msg}|%s"
+ msg=$(printf $msg $action)
+ fi
+ msg="${msg}]${MINUS_CHAR}"
+
+ msgs[1]=$msg
+
+ # Same shit with colors
+ msg="${nocolor_prompt}${vcs_symbols_color}(${vcs_type_color}%s${vcs_symbols_color})${vcs_sep_color}${MINUS_CHAR}${vcs_symbols_color}[${vcs_repo_color}%s${vcs_sep_color}/${vcs_branch_color}%s"
+ msg=$(printf $msg $vcs ${base/*\/} $branch)
+ if [ ! -z ${rev} ]; then
+ msg="${msg}${vcs_colon_color}:${vcs_rev_color}%s"
+ msg=$(printf $msg $rev)
+ fi
+ if [[ ! -z ${action} ]] ; then
+ msg="${msg}${nocolor_prompt}|${vcs_action_color}%s"
+ msg=$(printf $msg $action)
+ fi
+ msg="${msg}${vcs_symbols_color}]${line_color_prompt}${MINUS_CHAR}"
+ msgs[0]=$msg
+
+ return 0
+}
+
+# Uses -P option for cd in order to resolve symlinks
+vcs_realpath(){
+ (
+ cd -P $1 2>/dev/null && pwd
+ )
+}
+
+# Feature to detect a special dir, at the top of
+# the current repo
+detect_by_dir(){
+ local dirname=$1
+ local basedir="." realbasedir
+
+ realbasedir="$(vcs_realpath ${basedir})"
+ while [[ ${realbasedir} != '/' ]]; do
+ [[ -r ${realbasedir} ]] || return 1
+
+ # Tries to find detect_need_file (eg formats) in the dir
+ if [[ -n ${vcs_comm[detect_need_file]} ]] ; then
+ [[ -d ${basedir}/${dirname} ]] && \
+ [[ -e ${basedir}/${dirname}/${vcs_comm[detect_need_file]} ]] && \
+ break
+ else
+ [[ -d ${basedir}/${dirname} ]] && break
+ fi
+
+ basedir=${basedir}/..
+ realbasedir="$(vcs_realpath ${basedir})"
+ done
+
+ [[ ${realbasedir} == "/" ]] && return 1
+ vcs_comm[basedir]=${realbasedir}
+ return 0
+}
+
+# Git is powerfull
+git_detect(){
+ if check_command git && git rev-parse --is-inside-work-tree &> /dev/null; then
+ vcs_comm[gitdir]="$(git rev-parse --git-dir 2> /dev/null)" || return 1
+ if [[ -d ${vcs_comm[gitdir]}/svn ]] ; then vcs_comm[overwrite_name]='git-svn'
+ elif [[ -d ${vcs_comm[gitdir]}/refs/remotes/p4 ]] ; then vcs_comm[overwrite_name]='git-p4' ; fi
+ return 0
+ fi
+ return 1
+}
+
+# Mercurial isn't
+hg_detect(){
+ check_command hg || return 1
+ vcs_comm[detect_need_file]=store
+ detect_by_dir '.hg'
+ return $?
+}
+
+# .svn in each directories
+svn_detect() {
+ check_command svn || return 1
+ [[ -d ".svn" ]] && return 0
+ return 1
+}
+
+bzr_detect(){
+ check_command bzr || return 1
+ vcs_comm[detect_need_file]=branch/format
+ detect_by_dir '.bzr'
+ return $?
+}
+
+cdv_detect(){
+ check_command cdv || return 1
+ vcs_comm[detect_need_file]=format
+ detect_by_dir '.cdv'
+ return $?
+}
+
+cvs_detect(){
+ check_command svn || return 1
+ [[ -d "./CVS" ]] && [[ -r "./CVS/Repository" ]] && return 0
+ return 1
+}
+
+darcs_detect(){
+ check_command darcs || return 1
+ # darcs diff seems a good choice since big diff is not the
+ # common state
+ darcs diff 2> /dev/null || return 1
+ vcs_comm[basedir]=$(darcs show repo |awk '{if($1 == "Root:") print $2}')
+ return 0
+}
+
+# Find git's branch
+git_getbranch (){
+ local gitbranch gitdir=$1 tmp actiondir
+ local gitsymref='git symbolic-ref HEAD'
+
+ # In certain circumstances, we have to take into account
+ # actions
+ actiondir=''
+ for tmp in "${gitdir}/rebase-apply" \
+ "${gitdir}/rebase" \
+ "${gitdir}/../.dotest"; do
+ if [[ -d ${tmp} ]]; then
+ actiondir=${tmp}
+ break
+ fi
+ done
+ if [[ -n ${actiondir} ]]; then
+ gitbranch="$(${gitsymref} 2> /dev/null)"
+ [[ -z ${gitbranch} ]] && [[ -r ${actiondir}/head-name ]] \
+ && gitbranch="$(< ${actiondir}/head-name)"
+
+ # MERGE_HEAD state
+ elif [[ -f "${gitdir}/MERGE_HEAD" ]] ; then
+ gitbranch="$(eval $gitsymref 2> /dev/null)"
+ [[ -z ${gitbranch} ]] && gitbranch="$(< ${gitdir}/MERGE_HEAD)"
+
+ # rebase
+ elif [[ -d "${gitdir}/rebase-merge" ]] ; then
+ gitbranch="$(< ${gitdir}/rebase-merge/head-name)"
+
+ # dotest
+ elif [[ -d "${gitdir}/.dotest-merge" ]] ; then
+ gitbranch="$(< ${gitdir}/.dotest-merge/head-name)"
+
+ # Normal case
+ else
+ gitbranch="$(eval $gitsymref 2> /dev/null)"
+
+ # shit happens
+ if [[ $? -ne 0 ]] ; then
+ gitbranch="refs/tags/$(git describe --exact-match HEAD 2>/dev/null)"
+
+ # big shit happens
+ if [[ $? -ne 0 ]] ; then
+ gitbranch=$(< $gitdir/HEAD)
+ gitbranch="${gitbranch:0:7}..."
+ fi
+ fi
+ fi
+
+ # keep only the last part of gitbranch
+ printf '%s' "${gitbranch#refs/[^/]*/}"
+ return 0
+}
+
+git_getaction(){
+ local gitaction='' gitdir=$1
+ local tmp
+
+ for tmp in "${gitdir}/rebase-apply" \
+ "${gitdir}/rebase" \
+ "${gitdir}/../.dotest" ; do
+ if [[ -d ${tmp} ]] ; then
+ if [[ -f "${tmp}/rebasing" ]] ; then
+ gitaction="rebase"
+ elif [[ -f "${tmp}/applying" ]] ; then
+ gitaction="am"
+ else
+ gitaction="am/rebase"
+ fi
+ printf '%s' ${gitaction}
+ return 0
+ fi
+ done
+
+ for tmp in "${gitdir}/rebase-merge/interactive" \
+ "${gitdir}/.dotest-merge/interactive" ; do
+ if [[ -f "${tmp}" ]] ; then
+ printf '%s' "rebase-i"
+ return 0
+ fi
+ done
+
+ for tmp in "${gitdir}/rebase-merge" \
+ "${gitdir}/.dotest-merge" ; do
+ if [[ -d "${tmp}" ]] ; then
+ printf '%s' "rebase-m"
+ return 0
+ fi
+ done
+
+ if [[ -f "${gitdir}/MERGE_HEAD" ]] ; then
+ printf '%s' "merge"
+ return 0
+ fi
+
+ if [[ -f "${gitdir}/BISECT_LOG" ]] ; then
+ printf '%s' "bisect"
+ return 0
+ fi
+ return 1
+}
+
+git_get_data(){
+ local gitdir gitbase gitbranch gitaction
+
+ gitdir=${vcs_comm[gitdir]}
+ gitbranch="$(git_getbranch ${gitdir})"
+
+ if [[ -z ${gitdir} ]] || [[ -z ${gitbranch} ]] ; then
+ return 1
+ fi
+
+ vcs_adjust
+ gitaction="$(git_getaction ${gitdir})"
+ gitprefix=$(git rev-parse --show-prefix)
+ gitbase=${PWD%/${gitprefix%/}}
+ vcs_formats "${gitaction}" "${gitbranch}" "${gitbase}" ''
+ return 0
+}
+
+hg_get_data(){
+ local hgbranch hgbase file
+
+ hgbase=${vcs_comm[basedir]}
+
+ # Check if hg branch is efficient
+ hgbranch=$(hg branch)
+
+ vcs_formats '' "${hgbranch}" "${hgbase}" ''
+ return 0
+}
+
+svn_get_data(){
+ local svnbase svnbranch
+ local -a svninfo
+
+ svnbase="."
+ while [[ -d "${svnbase}/../.svn" ]]; do
+ svnbase="${svnbase}/.."
+ done
+ svnbase="$(vcs_realpath ${svnbase})"
+ svnrev=$(svn info | awk '{if($1 == "Révision :") print $2}')
+ svnbranch=$(svn info | awk '{if($1 == "URL :") print $2}'|awk -F "/" '{ print $NF }')
+
+ vcs_formats '' "${svnbranch}" "${svnbase}" "${svnrev}"
+ return 0
+}
+
+bzr_get_data(){
+ local bzrbase bzrrev bzrbranch bzrinfo
+
+ bzrbase=$(bzr info|awk '{if ($1 == "branch" && $2 == "root:") print $3}')
+ bzrbase="$(vcs_realpath ${bzrbase})"
+ bzrinfo=$(bzr version-info|awk '{if ($1 == "branch-nick:"||$1 == "revno:") print $2}')
+ bzrrev=$(echo $bzrinfo|awk '{print $1}')
+ bzrbranch=$(echo $bzrinfo|awk '{print $2}')
+
+ vcs_formats '' "${bzrbranch}" "${bzrbase}" "${bzrrev}"
+ return 0
+}
+
+cdv_get_data(){
+ local cdvbase
+
+ cdvbase=${vcs_comm[basedir]}
+ vcs_formats '' "${cdvbase/*\/}" "${cdvbase}" ''
+ return 0
+}
+
+cvs_get_data(){
+ local cvsbranch cvsbase basename
+
+ cvsbase="."
+ while [[ -d "${cvsbase}/../CVS" ]]; do
+ cvsbase="${cvsbase}/.."
+ done
+ cvsbase="$(vcs_realpath ${cvsbase})"
+ cvsbranch=$(< ./CVS/Repository)
+ basename=${cvsbase/*\/}
+ cvsbranch=${cvsbranch#${basename}/}
+
+ [[ -z ${cvsbranch} ]] && cvsbranch=${basename}
+ vcs_formats '' "${cvsbranch}" "${cvsbase}" ''
+ return 0
+}
+
+darcs_get_data(){
+ local darcsbase
+
+ darcsbase=${vcs_comm[basedir]}
+ vcs_formats '' "${darcsbase/*\/}" "${darcsbase}" ''
+ return 0
+}
+
+vcs_info(){
+ local -i found
+ local -ax msgs
+ local -Ax vcs_comm commands
+ local -x vcs
+ local -a vcss
+ local -A disabled
+
+ vcs="init"
+ vcss=(git hg darcs svn bzr cvs cdv)
+ disabled[cdv]=1
+ disabled[cvs]=1
+ disabled[bzr]=1
+ for i in $(seq 0 $(( ${#vcss[*]} - 1 ))); do
+ if [[ disabled[${vcss[$i]}] -eq 1 ]]; then
+ continue
+ fi
+ commands[${vcss[$i]}]=$( (which ${vcss[$i]} 2>/dev/null >&2 && which ${vcss[i]})||echo true);
+ done;
+
+ found=0
+ for vcs in ${vcss[*]}; do
+ if [[ disabled[${vcs}] -eq 1 ]]; then
+ continue
+ fi
+ ${vcs}_detect && found=1 && break
+ done
+
+ (( found == 1 )) && ${vcs}_get_data
+
+ if [ ${color_prompt} = "yes" ]; then
+ VCS_info=${msgs[0]}
+ else
+ VCS_info=${msgs[1]}
+ fi
+ VCS_size=${#msgs[1]}
+}