# # 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 __update_git_prompt_vars_if_git_ran() { case "$(history $(($HISTCMD - 1)))" in *git*) __git_set_prompt_variable esac } add-zsh-hook precmd __update_git_prompt_vars_if_git_ran __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