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

set GIT_WORK_TREE just to be sure
[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         _D="${GIT_DIR/$HOME/~}"
148         set -- "$_D" "$2" "${${1#$_D}%/}"
149         unset _D
150       fi
151       ;;
152     hg)
153       reporoot="$(__hg_get_reporoot)" ||
154         { error "could not determine hg repository root"; return 1 }
155       branch="$(__hg_get_branch)" ||
156         { error "could not determine hg branch"; return 1 }
157       eval set -- $(__vcs_get_prompt_path_components "$reporoot" "$branch")
158       ;;
159     bzr)
160       reporoot="$(__bzr_get_reporoot)" ||
161         { error "could not determine bzr repository root"; return 1 }
162       branch="$(__bzr_get_branch)" ||
163         { error "could not determine bzr branch"; return 1 }
164       eval set -- $(__vcs_get_prompt_path_components "$reporoot" "$branch")
165       ;;
166     *)
167       case "$repotype" in
168         NONE) :;;
169         *) warn "$repotype repositories not (yet) supported in the prompt";;
170       esac
171       local p="%${MAXLEN}<..<%~%<<"
172       #TODO find a better way so we don't have to nuke $psvar, but since the
173       #     %(nv.true.false) check for prompts checks element count, not
174       #     content, that's all we get for now
175       psvar=("${(%)p}")
176       return
177   esac
178
179   psvar[1,3]=($1 $2 $3)
180 }
181
182 if ! is_root; then
183   # too dangerous to be run as root
184
185   _update_vcs_prompt_vars_if_vcs_ran() {
186     local vcs="$(__vcs_get_repo_type)"
187     case "$(history $(($HISTCMD - 1)))" in
188       # $vcs appeared in last command, so be sure to update
189       *${vcs}*) __vcs_set_prompt_variables "$vcs"
190     esac
191   }
192   precmd_functions+=_update_vcs_prompt_vars_if_vcs_ran
193
194   _update_vcs_prompt_vars() {
195     __vcs_set_prompt_variables
196   }
197   chpwd_functions+=_update_vcs_prompt_vars
198
199   # call it once
200   _update_vcs_prompt_vars
201 fi
202
203 # vim:ft=zsh