]> git.madduck.net Git - etc/zsh.git/blob - .zsh/zshrc/60_vcsprompt

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

replace $HOME with ~ in GIT_DIR
[etc/zsh.git] / .zsh / zshrc / 60_vcsprompt
1 # zshrc/60_vcsprompt
2 #
3 # Make git information available to the prompt
4 #
5 # Copyright © 1994–2008 martin f. krafft <madduck@madduck.net>
6 # Released under the terms of the Artistic Licence 2.0
7 #
8 # Source repository: http://git.madduck.net/v/etc/zsh.git
9 #
10 # Shamelessly based on http://glandium.org/blog/?p=170
11 #
12
13 __git_get_reporoot()
14 {
15   # return the full path to the root of the current git repository
16   [ -d "$GIT_DIR" ] && echo "$GIT_DIR" && return 0
17   local relroot
18   relroot="$(git rev-parse --show-cdup 2>/dev/null)" || return 1
19   if [ -n "$relroot" ]; then
20     readlink -f "$relroot"
21   else
22     echo $PWD
23   fi
24 }
25
26 __git_get_branch()
27 {
28   # return the name of the git branch we're on
29   local ref
30   ref=$(git symbolic-ref -q HEAD 2>/dev/null \
31      || git-name-rev --name-only HEAD 2>/dev/null) || return 1
32   echo "${ref#refs/heads/}"
33 }
34
35 __hg_get_reporoot()
36 {
37   hg root
38 }
39
40 __hg_get_branch()
41 {
42   echo "hg:$(hg branch)"
43 }
44
45 __bzr_get_reporoot()
46 {
47   local reporoot
48   reporoot="$(bzr info | sed -rne 's, *branch root: ,,p')"
49   case "$reporoot" in
50     .) echo "$PWD";;
51     *) echo "$reporoot";;
52   esac
53 }
54
55 __bzr_get_branch()
56 {
57   local branch revno
58   bzr version-info | while read i j; do
59       case "$i" in
60         revno:) revno="$j";;
61         branch-nick:) branch="$j";;
62       esac
63     done
64   echo "bzr:${branch}@$revno"
65 }
66
67 __vcs_get_repo_type()
68 {
69   # return the type of the closest repository in the path hierarchy
70   local dir
71   while true; do
72     [ -d ${dir}.git ] && echo git && break
73     [ -d ${dir}.bzr ] && echo bzr && break
74     [ -d ${dir}.hg ] && echo hg && break
75     [ "$(readlink -f ${dir:-.})" = / ] && echo NONE && break
76     dir="../$dir"
77   done
78 }
79
80 __vcs_get_prompt_path_components()
81 {
82   # return formatted path components (prefix branch postfix) given
83   # the repository root and the branch.
84
85   # shortcut: if there are no arguments, return a default prompt
86   if [ -z "${1:-}" ]; then
87     pwdnamed="${(%):-%${_PROMPT_PATH_MAXLEN}<..<%~%<<}"
88     echo "$pwdnamed"
89     return
90   fi
91
92   local reporoot branch
93   reporoot="${1%%/}"
94   branch="$2"
95
96   # replace named directories in the PWD, we need thi for the proper component
97   # count later
98   local pwdnamed
99   pwdnamed="${(%):-%~}"
100
101   # store paths in arrays for component count calculation
102   typeset -la apwd apwdnamed areporoot
103   apwd=(${(s:/:)PWD})
104   apwdnamed=(${(s:/:)pwdnamed})
105   areporoot=(${(s:/:)reporoot})
106
107   # get the number of leading and trailing path components. Since we're using
108   # %~ later and then /home/madduck suddenly becomes ~, which is 1, not
109   # 2 components, we calculate the leading component count by using the named
110   # path and the number of post components
111   local precomps postcomps
112   postcomps=$(($#apwd - $#areporoot))
113   precomps=$(($#apwdnamed - $postcomps))
114
115   local postfix
116   (( $postcomps > 0 )) && postfix="${(%):-%${postcomps}~}"
117
118   # we don't want the prompt to get too long, so keep the total prompt length
119   # under $_PROMPT_PATH_MAXLEN (25), but ensure that the prefix is not shorter
120   # than $_PROMPT_PATH_MINLEN (10), no matter what
121   local prelen minlen prefix
122   prelen=$((${_PROMPT_PATH_MAXLEN:-25} - $#branch - $#postfix))
123   minlen=${_PROMPT_PATH_MINLEN:-10}
124   (( $prelen < $minlen )) && prelen=$minlen
125   prefix="${(%):-%${prelen}<..<%-${precomps}~%<<}"
126
127   echo "'$prefix'" "'$branch'" "'$postfix'"
128 }
129
130 __vcs_set_prompt_variables()
131 {
132   # set psvar[1..3] depending on repo type, or just psvar[1] if no repo found
133   local reporoot branch repotype
134   repotype="${1:-$(__vcs_get_repo_type)}"
135
136   case "$repotype" in
137     git)
138       reporoot="$(__git_get_reporoot)" ||
139         { error "could not determine git repository root"; return 1 }
140       branch="$(__git_get_branch)" ||
141         { error "could not determine git branch"; return 1 }
142       eval set -- $(__vcs_get_prompt_path_components "$reporoot" "$branch")
143       # poor man's replace until I find out how to do named dirs properly
144       # here:
145       [ -d "$GIT_DIR" ] && set -- "${GIT_DIR/$HOME/~}" "$2" "$1"
146       ;;
147     hg)
148       reporoot="$(__hg_get_reporoot)" ||
149         { error "could not determine hg repository root"; return 1 }
150       branch="$(__hg_get_branch)" ||
151         { error "could not determine hg branch"; return 1 }
152       eval set -- $(__vcs_get_prompt_path_components "$reporoot" "$branch")
153       ;;
154     bzr)
155       reporoot="$(__bzr_get_reporoot)" ||
156         { error "could not determine bzr repository root"; return 1 }
157       branch="$(__bzr_get_branch)" ||
158         { error "could not determine bzr branch"; return 1 }
159       eval set -- $(__vcs_get_prompt_path_components "$reporoot" "$branch")
160       ;;
161     *)
162       case "$repotype" in
163         NONE) :;;
164         *) warn "$repotype repositories not (yet) supported in the prompt";;
165       esac
166       local p="%${MAXLEN}<..<%~%<<"
167       #TODO find a better way so we don't have to nuke $psvar, but since the
168       #     %(nv.true.false) check for prompts checks element count, not
169       #     content, that's all we get for now
170       psvar=("${(%)p}")
171       return
172   esac
173
174   psvar[1,3]=($1 $2 $3)
175 }
176
177 if ! is_root; then
178   # too dangerous to be run as root
179
180   _update_vcs_prompt_vars_if_vcs_ran() {
181     local vcs="$(__vcs_get_repo_type)"
182     case "$(history $(($HISTCMD - 1)))" in
183       # $vcs appeared in last command, so be sure to update
184       *${vcs}*) __vcs_set_prompt_variables "$vcs"
185     esac
186   }
187   precmd_functions+=_update_vcs_prompt_vars_if_vcs_ran
188
189   _update_vcs_prompt_vars() {
190     __vcs_set_prompt_variables
191   }
192   chpwd_functions+=_update_vcs_prompt_vars
193
194   # call it once
195   _update_vcs_prompt_vars
196 fi
197
198 # vim:ft=zsh