]> 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:

no need for semicolons at eol
[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   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     [ "$(readlink -f ${dir:-.})" = / ] && echo NONE && break
75     dir="../$dir"
76   done
77 }
78
79 __vcs_get_prompt_path_components()
80 {
81   # return formatted path components (prefix branch postfix) given
82   # the repository root and the branch.
83
84   # shortcut: if there are no arguments, return a default prompt
85   if [ -z "${1:-}" ]; then
86     pwdnamed="%${_PROMPT_PATH_MAXLEN}<..<%~%<<"
87     pwdnamed="${(%)pwdnamed}"
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="${(%)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   if (( $postcomps > 0 )); then
117     postfix="%${postcomps}~"
118     postfix="${(%)postfix}"
119   fi
120
121   # we don't want the prompt to get too long, so keep the total prompt length
122   # under $_PROMPT_PATH_MAXLEN (25), but ensure that the prefix is not shorter
123   # than $_PROMPT_PATH_MINLEN (10), no matter what
124   local prelen minlen prefix
125   prelen=$((${_PROMPT_PATH_MAXLEN:-25} - $#branch - $#postfix))
126   minlen=${_PROMPT_PATH_MINLEN:-10}
127   (( $prelen < $minlen )) && prelen=$minlen
128   prefix="%${prelen}<..<%-${precomps}~%<<"
129   prefix="${(%)prefix}"
130
131   echo "$prefix" "$branch" "$postfix"
132 }
133
134 __vcs_set_prompt_variables()
135 {
136   # set psvar[1..3] depending on repo type, or just psvar[1] if no repo found
137   local reporoot branch repotype
138   repotype="${1:-$(__vcs_get_repo_type)}"
139
140   case "$repotype" in
141     git)
142       reporoot="$(__git_get_reporoot)" ||
143         { error "could not determine git repository root"; return 1 }
144       branch="$(__git_get_branch)" ||
145         { error "could not determine git branch"; return 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       ;;
153     bzr)
154       reporoot="$(__bzr_get_reporoot)" ||
155         { error "could not determine bzr repository root"; return 1 }
156       branch="$(__bzr_get_branch)" ||
157         { error "could not determine bzr branch"; return 1 }
158       ;;
159     *)
160       case "$repotype" in
161         NONE) :;;
162         *) warn "$repotype repositories not (yet) supported in the prompt";;
163       esac
164       local p="%${MAXLEN}<..<%~%<<"
165       #TODO find a better way so we don't have to nuke $psvar, but since the
166       #     %(nv.true.false) check for prompts checks element count, not
167       #     content, that's all we get for now
168       psvar=("${(%)p}")
169       return
170   esac
171
172   set -- $(__vcs_get_prompt_path_components "$reporoot" "$branch")
173   psvar[1]="$1"
174   psvar[2]="$2"
175   psvar[3]="$3"
176 }
177
178 if ! is_root; then
179   # too dangerous to be run as root
180
181   _update_vcs_prompt_vars_if_vcs_ran() {
182     local vcs="$(__vcs_get_repo_type)"
183     case "$(history $(($HISTCMD - 1)))" in
184       # $vcs appeared in last command, so be sure to update
185       *${vcs}*) __vcs_set_prompt_variables "$vcs"
186     esac
187   }
188   precmd_functions+=_update_vcs_prompt_vars_if_vcs_ran
189
190   _update_vcs_prompt_vars() {
191     __vcs_set_prompt_variables
192   }
193   chpwd_functions+=_update_vcs_prompt_vars
194
195   # call it once
196   _update_vcs_prompt_vars
197 fi
198
199 # vim:ft=zsh