]> git.madduck.net Git - etc/zsh.git/blob - .zsh/zshrc/85_vcs_prompt

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:

b608a6c7f806497bea37f9de897bbbde3f019bdf
[etc/zsh.git] / .zsh / zshrc / 85_vcs_prompt
1 # zshrc/85_git_prompt
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 __vcs_get_repo_type()
45 {
46   # return the type of the closest repository in the path hierarchy
47   local dir
48   while true; do
49     [ -d ${dir}.git ] && echo git && break
50     [ -d ${dir}.bzr ] && echo bzr && break
51     [ -d ${dir}.hg ] && echo hg && break
52     [ -d ${dir}.svn ] && echo svn && break
53     [ -d ${dir}.svk ] && echo svk && break
54     [ -d ${dir}CVS ] && echo cvs && break
55     [ "$(readlink -f ${dir:-.})" = / ] && echo NONE && break
56     dir="../$dir"
57   done
58 }
59
60 __vcs_get_prompt_path_components()
61 {
62   # return formatted path components (prefix branch postfix) given
63   # the repository root and the branch.
64
65   # shortcut: if there are no arguments, return a default prompt
66   if [ -z "${1:-}" ]; then
67     pwdnamed="%${_PROMPT_PATH_MAXLEN}<..<%~%<<"
68     pwdnamed="${(%)pwdnamed}"
69     echo "$pwdnamed"
70     return
71   fi
72
73   local reporoot branch
74   reporoot="${1%%/}"
75   branch="$2"
76
77   # replace named directories in the PWD, we need thi for the proper component
78   # count later
79   local pwdnamed="%~"
80   pwdnamed="${(%)pwdnamed}"
81
82   # store paths in arrays for component count calculation
83   typeset -la apwd apwdnamed areporoot
84   apwd=(${(s:/:)PWD})
85   apwdnamed=(${(s:/:)pwdnamed})
86   areporoot=(${(s:/:)reporoot})
87
88   # get the number of leading and trailing path components. Since we're using
89   # %~ later and then /home/madduck suddenly becomes ~, which is 1, not
90   # 2 components, we calculate the leading component count by using the named
91   # path and the number of post components
92   local precomps postcomps
93   postcomps=$(($#apwd - $#areporoot))
94   precomps=$(($#apwdnamed - $postcomps))
95
96   local postfix
97   if (( $postcomps > 0 )); then
98     postfix="%${postcomps}~"
99     postfix="${(%)postfix}"
100   fi
101
102   # we don't want the prompt to get too long, so keep the total prompt length
103   # under $_PROMPT_PATH_MAXLEN (25), but ensure that the prefix is not shorter
104   # than $_PROMPT_PATH_MINLEN (10), no matter what
105   local prelen minlen prefix
106   prelen=$((${_PROMPT_PATH_MAXLEN:-25} - $#branch - $#postfix))
107   minlen=${_PROMPT_PATH_MINLEN:-10}
108   (( $prelen < $minlen )) && prelen=$minlen
109   prefix="%${prelen}<..<%-${precomps}~%<<"
110   prefix="${(%)prefix}"
111
112   echo "$prefix" "$branch" "$postfix"
113 }
114
115 __vcs_set_prompt_variables()
116 {
117   # set psvar[1..3] depending on repo type, or just psvar[1] if no repo found
118   local reporoot branch repotype
119   repotype="${1:-$(__vcs_get_repo_type)}"
120
121   case "$repotype" in
122     git)
123       reporoot="$(__git_get_reporoot)" ||
124         { error "could not determine git repository root"; return 1 }
125       branch="$(__git_get_branch)" ||
126         { error "could not determine git branch"; return 1 }
127       ;;
128     hg)
129       reporoot="$(__hg_get_reporoot)" ||
130         { error "could not determine hg repository root"; return 1 }
131       branch="$(__hg_get_branch)" ||
132         { error "could not determine hg branch"; return 1 }
133       ;;
134     *)
135       case "$repotype" in
136         NONE) :;;
137         *) warn "$repotype repositories not (yet) supported in the prompt";;
138       esac
139       local p="%${MAXLEN}<..<%~%<<"
140       #TODO find a better way so we don't have to nuke $psvar, but since the
141       #     %(nv.true.false) check for prompts checks element count, not
142       #     content, that's all we get for now
143       psvar=("${(%)p}")
144       return
145   esac
146
147   set -- $(__vcs_get_prompt_path_components "$reporoot" "$branch")
148   psvar[1]="$1"
149   psvar[2]="$2"
150   psvar[3]="$3"
151 }
152
153 if ! is_root; then
154   # too dangerous to be run as root
155
156   _update_vcs_prompt_vars_if_vcs_ran() {
157     local vcs="$(__vcs_get_repo_type)"
158     case "$(history $(($HISTCMD - 1)))" in
159       # $vcs appeared in last command, so be sure to update
160       *${vcs}*) __vcs_set_prompt_variables "$vcs"
161     esac
162   }
163   precmd_functions+=_update_vcs_prompt_vars_if_vcs_ran
164
165   _update_vcs_prompt_vars() {
166     __vcs_set_prompt_variables
167   }
168   chpwd_functions+=_update_vcs_prompt_vars
169
170   # call it once
171   _update_vcs_prompt_vars
172 fi
173
174 # vim:ft=zsh