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; 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; cached=(${(f)"$(gitdiffstat --cached | output cached)"})
85 local changed; 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
144 # unless we're on a network filesystem:
145 if __on_networkfs; then
151 [ -d ${dir}.git ] && echo git && break
152 [ -d "$GIT_DIR" ] && echo git && break
153 [ -d ${dir}.bzr ] && echo bzr && break
154 [ -d ${dir}.hg ] && echo hg && break
155 [ "$(readlink -f ${dir:-.})" = / ] && echo NONE && break
160 __get_prompt_path_len() {
163 zstyle -s ":madduck:prompt:$PWD" path-${1}len result
164 [ -z "$result" ] && zstyle -s ':madduck:prompt:default' path-${1}len result
168 __vcs_get_prompt_path_components()
171 # return formatted path components (prefix branch postfix) given
172 # the repository root and the branch.
175 MAXLEN=$(__get_prompt_path_len max)
176 MINLEN=$(__get_prompt_path_len min)
178 # shortcut: if there are no arguments, return a default prompt
179 if [ -z "${1:-}" ]; then
180 pwdnamed="${(%):-%${MAXLEN}<…<%~%<<}"
185 local reporoot branch
189 # replace named directories in the PWD, we need thi for the proper component
192 pwdnamed="${(%):-%~}"
194 # store paths in arrays for component count calculation
195 typeset -la apwd apwdnamed areporoot
197 apwdnamed=(${(s:/:)pwdnamed})
198 areporoot=(${(s:/:)reporoot})
200 # get the number of leading and trailing path components. Since we're using
201 # %~ later and then /home/madduck suddenly becomes ~, which is 1, not
202 # 2 components, we calculate the leading component count by using the named
203 # path and the number of post components
204 local precomps postcomps
205 postcomps=$(($#apwd - $#areporoot))
206 precomps=$(($#apwdnamed - $postcomps))
209 (( $postcomps > 0 )) && postfix="${(%):-%${postcomps}~}"
211 # we don't want the prompt to get too long, so keep the total prompt length
212 # under $MAXLEN, but ensure that the prefix is not shorter
213 # than $MINLEN, no matter what
214 local prelen minlen prefix
215 prelen=$((${MAXLEN} - $#branch - $#postfix))
217 (( $prelen < $minlen )) && prelen=$minlen
218 prefix="${(%):-%${prelen}<…<%-${precomps}~%<<}"
220 echo "'$prefix'" "'$branch'" "'$postfix'"
223 __vcs_set_prompt_variables()
226 # set psvar[1..3] depending on repo type, or just psvar[1] if no repo found
227 local reporoot branch repotype
228 repotype="${1:-$(__vcs_get_repo_type)}"
232 reporoot="$(__git_get_reporoot)" ||
233 { zerror "could not determine git repository root"; return 1 }
234 branch="$(__git_get_branch)" ||
235 { zerror "could not determine git branch"; return 1 }
236 if [ -n "$VCSH_REPO_NAME" ]; then
237 # if vcsh is used to get a subshell, then the repo root is the home
238 # directory, but we want to indicate the vcsh context too:
239 eval set -- $(__vcs_get_prompt_path_components "$HOME" "$branch")
240 set -- "vcsh:$VCSH_REPO_NAME" "$2" "$1${3:+/$3}"
242 eval set -- $(__vcs_get_prompt_path_components "$reporoot" "$branch")
243 if [ -d "$GIT_DIR" ]; then
244 # poor man's replace until I find out how to do named dirs properly
246 local _D="${GIT_DIR/$HOME/~}"
247 set -- "$_D" "$2" "${${1#$_D}%/}"
252 reporoot="$(__hg_get_reporoot)" ||
253 { zerror "could not determine hg repository root"; return 1 }
254 branch="$(__hg_get_branch)" ||
255 { zerror "could not determine hg branch"; return 1 }
256 eval set -- $(__vcs_get_prompt_path_components "$reporoot" "$branch")
259 reporoot="$(__bzr_get_reporoot)" ||
260 { zerror "could not determine bzr repository root"; return 1 }
261 branch="$(__bzr_get_branch)" ||
262 { zerror "could not determine bzr branch"; return 1 }
263 eval set -- $(__vcs_get_prompt_path_components "$reporoot" "$branch")
268 *) warn "$repotype repositories not (yet) supported in the prompt";;
271 MAXLEN=$(__get_prompt_path_len max)
272 local p="%${MAXLEN}<…<%~%<<"
273 #TODO find a better way so we don't have to nuke $psvar, but since the
274 # %(nv.true.false) check for prompts checks element count, not
275 # content, that's all we get for now
280 psvar[1,3]=($1 $2 $3)
283 __vcs_print_preprompt()
286 local repotype="${1:-$(__vcs_get_repo_type)}"
290 __git_print_preprompt
296 # too dangerous to be run as root
297 autoload -U add-zsh-hook
299 _update_vcs_prompt_vars_if_vcs_ran() {
300 local vcs="$(__vcs_get_repo_type)"
301 case "$vcs/$(history $(($HISTCMD - 1)))" in
302 # $vcs appeared in last command, so be sure to update
305 */*${vcs}*) __vcs_set_prompt_variables "$vcs"
308 add-zsh-hook precmd _update_vcs_prompt_vars_if_vcs_ran
310 _update_vcs_prompt_vars() {
311 __vcs_set_prompt_variables
313 add-zsh-hook chpwd _update_vcs_prompt_vars
316 [[ $? -eq 0 ]] && __vcs_print_preprompt
318 add-zsh-hook precmd _print_preprompt
321 _update_vcs_prompt_vars
324 function make_ps1() {
325 # start with '+' if in a subshell
328 # the machine name, bold or underlined based on non-root/root
331 echo -n "%${ps1_hl:=B}%m%${(L)ps1_hl}"
333 # if we're in a Debian chroot, make that stand out
334 echo -n "${DEBIAN_CHROOT:+/%S$DEBIAN_CHROOT%s}"
336 # we end this with a :
339 # now comes the working directory, composed from parts in $psvar,
340 # which is managed by $ZDOTDIR/zshrc/06-vcsprompt
341 echo -n '%1v%(2v.|%B%2v%b|.)%(3v.%3v.)'
343 # and we finish with #/% for root/non-root, and a space
349 PS2="%{$fg[red]%}%_>%{$reset_color%}"
351 function make_rps1() {
352 # First, a comment character and parens
355 # Next, if the returncode was non-zero, make it stand-out
356 # and include a trailing space
357 echo -n "%(0?..%{$fg[red]%}%S%?%s%{$reset_color%} )"
359 # If there are background jobs, print their number, followed by
363 # and then the terminal line we're using
366 # this concludes the first part, but there's more
369 # the timestamp will finish it off:
370 echo -n '%D{%d %H:%M:%S.%.}'
373 typeset -g RPS1="$(make_rps1)"