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

integrate local changes
[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 "$GIT_DIR" ] && echo git && break
74     [ -d ${dir}.bzr ] && echo bzr && break
75     [ -d ${dir}.hg ] && echo hg && break
76     [ "$(readlink -f ${dir:-.})" = / ] && echo NONE && break
77     dir="../$dir"
78   done
79 }
80
81 __vcs_get_prompt_path_components()
82 {
83   # return formatted path components (prefix branch postfix) given
84   # the repository root and the branch.
85
86   # shortcut: if there are no arguments, return a default prompt
87   if [ -z "${1:-}" ]; then
88     pwdnamed="${(%):-%${_PROMPT_PATH_MAXLEN}<..<%~%<<}"
89     echo "$pwdnamed"
90     return
91   fi
92
93   local reporoot branch
94   reporoot="${1%%/}"
95   branch="$2"
96
97   # replace named directories in the PWD, we need thi for the proper component
98   # count later
99   local pwdnamed
100   pwdnamed="${(%):-%~}"
101
102   # store paths in arrays for component count calculation
103   typeset -la apwd apwdnamed areporoot
104   apwd=(${(s:/:)PWD})
105   apwdnamed=(${(s:/:)pwdnamed})
106   areporoot=(${(s:/:)reporoot})
107
108   # get the number of leading and trailing path components. Since we're using
109   # %~ later and then /home/madduck suddenly becomes ~, which is 1, not
110   # 2 components, we calculate the leading component count by using the named
111   # path and the number of post components
112   local precomps postcomps
113   postcomps=$(($#apwd - $#areporoot))
114   precomps=$(($#apwdnamed - $postcomps))
115
116   local postfix
117   (( $postcomps > 0 )) && postfix="${(%):-%${postcomps}~}"
118
119   # we don't want the prompt to get too long, so keep the total prompt length
120   # under $_PROMPT_PATH_MAXLEN (25), but ensure that the prefix is not shorter
121   # than $_PROMPT_PATH_MINLEN (10), no matter what
122   local prelen minlen prefix
123   prelen=$((${_PROMPT_PATH_MAXLEN:-25} - $#branch - $#postfix))
124   minlen=${_PROMPT_PATH_MINLEN:-10}
125   (( $prelen < $minlen )) && prelen=$minlen
126   prefix="${(%):-%${prelen}<..<%-${precomps}~%<<}"
127
128   echo "'$prefix'" "'$branch'" "'$postfix'"
129 }
130
131 __vcs_set_prompt_variables()
132 {
133   # set psvar[1..3] depending on repo type, or just psvar[1] if no repo found
134   local reporoot branch repotype
135   repotype="${1:-$(__vcs_get_repo_type)}"
136
137   case "$repotype" in
138     git)
139       reporoot="$(__git_get_reporoot)" ||
140         { error "could not determine git repository root"; return 1 }
141       branch="$(__git_get_branch)" ||
142         { error "could not determine git branch"; return 1 }
143       eval set -- $(__vcs_get_prompt_path_components "$reporoot" "$branch")
144       if [ -d "$GIT_DIR" ]; then
145         # poor man's replace until I find out how to do named dirs properly
146         # here:
147         local _D="${GIT_DIR/$HOME/~}"
148         set -- "$_D" "$2" "${${1#$_D}%/}"
149       fi
150       ;;
151     hg)
152       reporoot="$(__hg_get_reporoot)" ||
153         { error "could not determine hg repository root"; return 1 }
154       branch="$(__hg_get_branch)" ||
155         { error "could not determine hg branch"; return 1 }
156       eval set -- $(__vcs_get_prompt_path_components "$reporoot" "$branch")
157       ;;
158     bzr)
159       reporoot="$(__bzr_get_reporoot)" ||
160         { error "could not determine bzr repository root"; return 1 }
161       branch="$(__bzr_get_branch)" ||
162         { error "could not determine bzr branch"; return 1 }
163       eval set -- $(__vcs_get_prompt_path_components "$reporoot" "$branch")
164       ;;
165     *)
166       case "$repotype" in
167         NONE) :;;
168         *) warn "$repotype repositories not (yet) supported in the prompt";;
169       esac
170       local p="%${MAXLEN}<..<%~%<<"
171       #TODO find a better way so we don't have to nuke $psvar, but since the
172       #     %(nv.true.false) check for prompts checks element count, not
173       #     content, that's all we get for now
174       psvar=("${(%)p}")
175       return
176   esac
177
178   psvar[1,3]=($1 $2 $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