]> git.madduck.net Git - etc/zsh.git/blob - .zsh/zshrc/85_vcs_prompt

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:

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