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.
4 # Copyright © 1994–2017 martin f. krafft <madduck@madduck.net>
5 # Released under the terms of the Artistic Licence 2.0
7 # Source repository: http://git.madduck.net/v/etc/zsh.git
9 # vcs stuff shamelessly based on http://glandium.org/blog/?p=170
12 zstyle -m :madduck:prompt:default path-maxlen '*' \
13 || zstyle :madduck:prompt:default path-maxlen 25
14 zstyle -m :madduck:prompt:default path-minlen '*' \
15 || zstyle :madduck:prompt:default path-minlen 10
20 case $(df -T . | sed -rne '$s,^[^[:space:]]+[[:space:]]+([^[:space:]]+).*,\1,p') in
29 # return the full path to the root of the current git repository
30 [ -d "$GIT_DIR" ] && echo "$GIT_DIR" && return 0
31 local dir; dir="$PWD/$(git rev-parse --show-cdup)"
32 # do not use --show-toplevel because it resolves symlinks
39 # use oh-my-zsh prompt info function if it exists
40 $(command -v git_prompt_info) && return
42 # return the name of the git branch we're on
44 gitdir="$(git rev-parse --git-dir)"
45 ref=$(git --git-dir="$gitdir" symbolic-ref -q HEAD 2>/dev/null \
46 || git --git-dir="$gitdir" name-rev --name-only HEAD 2>/dev/null) || return 1
47 echo "${ref#refs/heads/}"
50 __git_print_preprompt()
53 [ "$(git config --get core.bare)" = false ] || return
54 __on_networkfs && return
56 local COLUMNS=${COLUMNS:-80}
57 local LINES=${LINES:-25}
62 local output=(${(f)"$(cat)"})
64 [[ ${#output} -ge 1 ]] || return
66 local statl="$(echo ${output[-1]} | sed -re 's@^\s*([0-9]+)[^,]+(, ([0-9]+) [^(]+\(([-+])\))(, ([0-9]+) [^(]+\(([-+])\))?@\1/\4\3/\7\6@')"
68 if [[ ${output[-2]## } = '...' ]]; then
69 print "${title} (${statl%/}, abbrev.):"
70 print "${(F)output[1,-3]}"
73 print "${title} (${statl%/}):"
74 print "${(F)output[1,-2]}"
78 function gitdiffstat() {
80 local common_options="--stat=$((COLUMNS/2-1)),$((COLUMNS/4-2)),$(($LINES/3)) --relative"
81 eval git diff $common_options "$@" 2>/dev/null
84 local cached=(${(f)"$(gitdiffstat --cached | output cached)"})
85 local changed=(${(f)"$(gitdiffstat | output changed)"})
88 [[ $max -lt ${#cached} ]] && max=${#cached}
90 ((max == 0)) && return
92 local width=$(((COLUMNS-3)/2))
94 if (( ${#cached} > 0 && ${#changed} > 0 )); then
96 for (( i=1 ; i <= max ; i++ )) do
97 printf "%-${width}s │ %-${width}s\n" "${cached[$i]}" "${changed[$i]}"
100 print ${(F)cached}${(F)changed}
113 echo "hg:$(hg branch)"
120 reporoot="$(bzr info | sed -rne 's, *branch root: ,,p')"
123 *) echo "$reporoot";;
131 bzr version-info | while read i j; do
134 branch-nick:) branch="$j";;
137 echo "bzr:${branch}@$revno"
140 __vcs_get_repo_type()
143 # return the type of the closest repository in the path hierarchy
146 [ -d ${dir}.git ] && echo git && break
147 [ -d "$GIT_DIR" ] && echo git && break
148 [ -d ${dir}.bzr ] && echo bzr && break
149 [ -d ${dir}.hg ] && echo hg && break
150 [ "$(readlink -f ${dir:-.})" = / ] && echo NONE && break
155 __get_prompt_path_len() {
158 zstyle -s ":madduck:prompt:$PWD" path-${1}len result
159 [ -z "$result" ] && zstyle -s ':madduck:prompt:default' path-${1}len result
163 __vcs_get_prompt_path_components()
166 # return formatted path components (prefix branch postfix) given
167 # the repository root and the branch.
170 MAXLEN=$(__get_prompt_path_len max)
171 MINLEN=$(__get_prompt_path_len min)
173 # shortcut: if there are no arguments, return a default prompt
174 if [ -z "${1:-}" ]; then
175 pwdnamed="${(%):-%${MAXLEN}<…<%~%<<}"
180 local reporoot branch
184 # replace named directories in the PWD, we need thi for the proper component
187 pwdnamed="${(%):-%~}"
189 # store paths in arrays for component count calculation
190 typeset -la apwd apwdnamed areporoot
192 apwdnamed=(${(s:/:)pwdnamed})
193 areporoot=(${(s:/:)reporoot})
195 # get the number of leading and trailing path components. Since we're using
196 # %~ later and then /home/madduck suddenly becomes ~, which is 1, not
197 # 2 components, we calculate the leading component count by using the named
198 # path and the number of post components
199 local precomps postcomps
200 postcomps=$(($#apwd - $#areporoot))
201 precomps=$(($#apwdnamed - $postcomps))
204 (( $postcomps > 0 )) && postfix="${(%):-%${postcomps}~}"
206 # we don't want the prompt to get too long, so keep the total prompt length
207 # under $MAXLEN, but ensure that the prefix is not shorter
208 # than $MINLEN, no matter what
209 local prelen minlen prefix
210 prelen=$((${MAXLEN} - $#branch - $#postfix))
212 (( $prelen < $minlen )) && prelen=$minlen
213 prefix="${(%):-%${prelen}<…<%-${precomps}~%<<}"
215 echo "'$prefix'" "'$branch'" "'$postfix'"
218 __vcs_set_prompt_variables()
221 # set psvar[1..3] depending on repo type, or just psvar[1] if no repo found
222 local reporoot branch repotype
223 repotype="${1:-$(__vcs_get_repo_type)}"
227 reporoot="$(__git_get_reporoot)" ||
228 { zerror "could not determine git repository root"; return 1 }
229 branch="$(__git_get_branch)" ||
230 { zerror "could not determine git branch"; return 1 }
231 if [ -n "$VCSH_REPO_NAME" ]; then
232 # if vcsh is used to get a subshell, then the repo root is the home
233 # directory, but we want to indicate the vcsh context too:
234 eval set -- $(__vcs_get_prompt_path_components "$HOME" "$branch")
235 set -- "vcsh:$VCSH_REPO_NAME" "$2" "$1${3:+/$3}"
237 eval set -- $(__vcs_get_prompt_path_components "$reporoot" "$branch")
238 if [ -d "$GIT_DIR" ]; then
239 # poor man's replace until I find out how to do named dirs properly
241 local _D="${GIT_DIR/$HOME/~}"
242 set -- "$_D" "$2" "${${1#$_D}%/}"
247 reporoot="$(__hg_get_reporoot)" ||
248 { zerror "could not determine hg repository root"; return 1 }
249 branch="$(__hg_get_branch)" ||
250 { zerror "could not determine hg branch"; return 1 }
251 eval set -- $(__vcs_get_prompt_path_components "$reporoot" "$branch")
254 reporoot="$(__bzr_get_reporoot)" ||
255 { zerror "could not determine bzr repository root"; return 1 }
256 branch="$(__bzr_get_branch)" ||
257 { zerror "could not determine bzr branch"; return 1 }
258 eval set -- $(__vcs_get_prompt_path_components "$reporoot" "$branch")
263 *) warn "$repotype repositories not (yet) supported in the prompt";;
266 MAXLEN=$(__get_prompt_path_len max)
267 local p="%${MAXLEN}<…<%~%<<"
268 #TODO find a better way so we don't have to nuke $psvar, but since the
269 # %(nv.true.false) check for prompts checks element count, not
270 # content, that's all we get for now
275 psvar[1,3]=($1 $2 $3)
278 __vcs_print_preprompt()
281 local repotype="${1:-$(__vcs_get_repo_type)}"
285 __git_print_preprompt
291 # too dangerous to be run as root
292 autoload -U add-zsh-hook
294 _update_vcs_prompt_vars_if_vcs_ran() {
295 local vcs="$(__vcs_get_repo_type)"
296 case "$(history $(($HISTCMD - 1)))" in
297 # $vcs appeared in last command, so be sure to update
298 *${vcs}*) __vcs_set_prompt_variables "$vcs"
301 add-zsh-hook precmd _update_vcs_prompt_vars_if_vcs_ran
303 _update_vcs_prompt_vars() {
304 __vcs_set_prompt_variables
306 add-zsh-hook chpwd _update_vcs_prompt_vars
309 [[ $? -eq 0 ]] && __vcs_print_preprompt
311 add-zsh-hook precmd _print_preprompt
314 _update_vcs_prompt_vars
317 function make_ps1() {
318 # start with '+' if in a subshell
321 # the machine name, bold or underlined based on non-root/root
324 echo -n "%${ps1_hl:=B}%m%${(L)ps1_hl}"
326 # if we're in a Debian chroot, make that stand out
327 echo -n "${DEBIAN_CHROOT:+/%S$DEBIAN_CHROOT%s}"
329 # we end this with a :
332 # now comes the working directory, composed from parts in $psvar,
333 # which is managed by $ZDOTDIR/zshrc/06-vcsprompt
334 echo -n '%1v%(2v.|%B%2v%b|.)%(3v.%3v.)'
336 # and we finish with #/% for root/non-root, and a space
342 PS2="%{$fg[red]%}%_>%{$reset_color%}"
344 function make_rps1() {
345 # First, a comment character and parens
348 # Next, if the returncode was non-zero, make it stand-out
349 # and include a trailing space
350 echo -n "%(0?..%{$fg[red]%}%S%?%s%{$reset_color%} )"
352 # If there are background jobs, print their number, followed by
356 # and then the terminal line we're using
359 # this concludes the first part, but there's more
362 # the timestamp will finish it off:
363 echo -n '%D{%d %H:%M:%S.%.}'