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

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