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

beautify prompt when GIT_DIR is set
[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       if [ -d "$GIT_DIR" ]; then
144         # poor man's replace until I find out how to do named dirs properly
145         # here:
146         _D="${GIT_DIR/$HOME/~}"
147         set -- "$_D" "$2" "${${1#$_D}%/}"
148         unset _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