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

create tmpdir if not present
[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     pwdnamed="${(%)pwdnamed}"
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="${(%)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   if (( $postcomps > 0 )); then
118     postfix="%${postcomps}~"
119     postfix="${(%)postfix}"
120   fi
121
122   # we don't want the prompt to get too long, so keep the total prompt length
123   # under $_PROMPT_PATH_MAXLEN (25), but ensure that the prefix is not shorter
124   # than $_PROMPT_PATH_MINLEN (10), no matter what
125   local prelen minlen prefix
126   prelen=$((${_PROMPT_PATH_MAXLEN:-25} - $#branch - $#postfix))
127   minlen=${_PROMPT_PATH_MINLEN:-10}
128   (( $prelen < $minlen )) && prelen=$minlen
129   prefix="%${prelen}<..<%-${precomps}~%<<"
130   prefix="${(%)prefix}"
131
132   echo "$prefix" "$branch" "$postfix"
133 }
134
135 __vcs_set_prompt_variables()
136 {
137   # set psvar[1..3] depending on repo type, or just psvar[1] if no repo found
138   local reporoot branch repotype
139   repotype="${1:-$(__vcs_get_repo_type)}"
140
141   case "$repotype" in
142     git)
143       reporoot="$(__git_get_reporoot)" ||
144         { error "could not determine git repository root"; return 1 }
145       branch="$(__git_get_branch)" ||
146         { error "could not determine git branch"; return 1 }
147       set -- $(__vcs_get_prompt_path_components "$reporoot" "$branch")
148       [ -d "$GIT_DIR" ] && set -- "$GIT_DIR" "$2" "$1"
149       set +x
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       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       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]="$1"
179   psvar[2]="$2"
180   psvar[3]="$3"
181 }
182
183 if ! is_root; then
184   # too dangerous to be run as root
185
186   _update_vcs_prompt_vars_if_vcs_ran() {
187     local vcs="$(__vcs_get_repo_type)"
188     case "$(history $(($HISTCMD - 1)))" in
189       # $vcs appeared in last command, so be sure to update
190       *${vcs}*) __vcs_set_prompt_variables "$vcs"
191     esac
192   }
193   precmd_functions+=_update_vcs_prompt_vars_if_vcs_ran
194
195   _update_vcs_prompt_vars() {
196     __vcs_set_prompt_variables
197   }
198   chpwd_functions+=_update_vcs_prompt_vars
199
200   # call it once
201   _update_vcs_prompt_vars
202 fi
203
204 # vim:ft=zsh