From a0d7ac1318b3019819e7f2108a924319439c5a39 Mon Sep 17 00:00:00 2001 From: "martin f. krafft" Date: Sun, 11 Aug 2019 07:24:44 +1200 Subject: [PATCH] Update Git shell integration --- .zsh/zshrc/parts.d/50-git | 120 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 .zsh/zshrc/parts.d/50-git diff --git a/.zsh/zshrc/parts.d/50-git b/.zsh/zshrc/parts.d/50-git new file mode 100644 index 0000000..da11bf8 --- /dev/null +++ b/.zsh/zshrc/parts.d/50-git @@ -0,0 +1,120 @@ +# +# Git shell integration +# +# Copyright © 2018 martin f. krafft +# Released under the terms of the Artistic Licence 2.0 +# +# Source repository: http://git.madduck.net/v/etc/zsh.git +# + +__is_git_repo() +{ + emulate -L zsh + git rev-parse --is-inside-work-tree >/dev/null 2>&1 +} + +__git_get_reporoot() +{ + emulate -L zsh + # return the full path to the root of the current git repository + [ -d "$GIT_DIR" ] && echo "$GIT_DIR" && return 0 + local dir; dir="$PWD/$(git rev-parse --show-cdup)" + # do not use --show-toplevel because it resolves symlinks + echo $dir:a +} + +__git_get_branch() +{ + emulate -L zsh + # use oh-my-zsh prompt info function if it exists + $(command -v git_prompt_info) && return + + # return the name of the git branch we're on + local ref gitdir + gitdir="$(git rev-parse --git-dir)" + ref=$(git --git-dir="$gitdir" symbolic-ref -q HEAD 2>/dev/null \ + || git --git-dir="$gitdir" name-rev --name-only HEAD 2>/dev/null) || return 1 + echo "${ref#refs/heads/}" +} + +__git_set_prompt_variable() { + __is_git_repo || return + + local reporoot="$(__git_get_reporoot)" || + { zerror "could not determine git repository root"; return 1 } + local branch="$(__git_get_branch)" || + { zerror "could not determine git branch"; return 1 } + if [ -n "$VCSH_REPO_NAME" ]; then + # if vcsh is used to get a subshell, then the repo root is the home + # directory, but we want to indicate the vcsh context too: + eval set -- $(__vcs_get_prompt_path_components "$HOME" "$branch") + set -- "vcsh:$VCSH_REPO_NAME" "$2" "$1${3:+/$3}" + else + eval set -- $(__vcs_get_prompt_path_components "$reporoot" "$branch") + if [ -d "$GIT_DIR" ]; then + set -- "${(D)GIT_DIR}" "$2" "${${1#$_D}%/}" + fi + fi + psvar[4]="$1${2:+|%B$2%b|}${3:-}" +} +add-zsh-hook chpwd __git_set_prompt_variable +__git_set_prompt_variable + +__git_print_preprompt() +{ + [[ $? -eq 0 ]] || return + emulate -L zsh + __is_git_repo || return + [ "$(git config --get core.bare)" = false ] || return + __on_networkfs && return + + local COLUMNS=${COLUMNS:-80} + local LINES=${LINES:-25} + + function output() { + emulate -L zsh + local title="$@" + local output; output=(${(f)"$(cat)"}) + + [[ ${#output} -ge 1 ]] || return + + local statl="$(echo ${output[-1]} | sed -re 's@^\s*([0-9]+)[^,]+(, ([0-9]+) [^(]+\(([-+])\))(, ([0-9]+) [^(]+\(([-+])\))?@\1/\4\3/\7\6@')" + + if [[ ${output[-2]## } = '...' ]]; then + print "${title} (${statl%/}, abbrev.):" + print "${(F)output[1,-3]}" + print " …" + else + print "${title} (${statl%/}):" + print "${(F)output[1,-2]}" + fi + } + + function gitdiffstat() { + emulate -L zsh + local common_options="--stat=$((COLUMNS/2-1)),$((COLUMNS/4-2)),$(($LINES/3)) --relative" + eval git diff $common_options "$@" 2>/dev/null + } + + local cached; cached=(${(f)"$(gitdiffstat --cached | output cached)"}) + local changed; changed=(${(f)"$(gitdiffstat | output changed)"}) + + local max=${#changed} + [[ $max -lt ${#cached} ]] && max=${#cached} + + ((max == 0)) && return + + local width=$(((COLUMNS-3)/2)) + + if (( ${#cached} > 0 && ${#changed} > 0 )); then + local i + for (( i=1 ; i <= max ; i++ )) do + printf "%-${width}s │ %-${width}s\n" "${cached[$i]}" "${changed[$i]}" + done + else + print ${(F)cached}${(F)changed} + fi +} +add-zsh-hook precmd __git_print_preprompt + +# vim:ft=zsh -- 2.39.2