diff --git a/gitstatus.plugin.zsh b/gitstatus.plugin.zsh index 0b6e108..2cd699c 100755 --- a/gitstatus.plugin.zsh +++ b/gitstatus.plugin.zsh @@ -1,103 +1,130 @@ #!/usr/bin/zsh -### -# Unset global variables -# Globals: all -# Arguments: none -### -function sanitize() { - unset GIT_CURRENT_BRANCH GIT_STATUS - unset GIT_STAGED GIT_MODIFIED GIT_UNTRACKED GIT_DELETED - unset GIT_COMMITS_BEHIND GIT_COMMITS_AHEAD GIT_COMMITS_STATUS - git rev-parse --git-dir &>/dev/null || return 1 +function main() { + is_in_git_repository || return 1 + + parse_git_status + local modified="${STATUS[1]}" + local staged="${STATUS[2]}" + local deleted="${STATUS[3]}" + local untracked="${STATUS[4]}" + unset STATUS + + git_grab_current_branch + local branch="$REPLY" + + git_grab_remote_branch + local remote="$REPLY" + + [[ ! -z "$remote" ]] \ + && get_differences_between_remote_and_local \ + && local remote_local_diffs="$REPLY" + + git_determine_color $modified $staged $deleted $untracked + local color="$REPLY" + + (( modified > 0 )) \ + && modified="!$modified " + (( staged > 0 )) \ + && staged="+$staged " + (( deleted > 0 )) \ + && deleted="-$deleted " + (( untracked > 0 )) \ + && untracked="?$untracked" + + local output="${color}" + output+=" $branch " + output+="$local_remote_diffs" + output+="$modified" + output+="$staged" + output+="$deleted" + output+="$untracked" + output+=$'\e[0m' + + sed 's/[ ]+$//' <<<"$output" # remove trailing whitespace } ### -# Get necessary information from git, like current branch, amount of modified -# files etc. to then put them all into a global variable, GIT_STATUS +# Check if we're in a git repository # Globals: none # Arguments: none ### -function parse_git_status() { - local modified_files=0 staged_files=0 untracked_files=0 deleted_files=0 - local git_has_changes=0 - GIT_CURRENT_BRANCH="$(git branch --show-current)" +function is_in_git_repository() +{ + git rev-parse --git-dir &>/dev/null || return 1 +} +function git_grab_current_branch() +{ + typeset -g REPLY="$(git branch --show-current)" +} + +function git_grab_remote_branch() +{ + local symbolic_ref="$(git symbolic-ref -q HEAD)" + typeset -g REPLY="$(git for-each-ref --format='%(upstream:short)' $symbolic_ref)" +} + +### +# Find how many things have changed since last commit +# Globals: none +# Arguments: none +### +function parse_git_status() +{ git status --porcelain=v1 | while IFS= read -r status_line; do - git_has_changes=1 case "$status_line" in ' M '*) - ((modified_files++)) + ((modified++)) ;; 'A '*|'M '*) - ((staged_files++)) + ((staged++)) ;; ' D '*) - ((deleted_files++)) + ((deleted++)) ;; '?? '*) - ((untracked_files++)) + ((untracked++)) ;; 'MM '*) - ((staged_files++)) - ((modified_files++)) + ((staged++)) + ((modified++)) ;; esac done - GIT_REMOTE_BRANCH=$(git for-each-ref --format='%(upstream:short)' "$(git symbolic-ref -q HEAD)") - local ahead_behind_status commits_behind commits_ahead - if [[ ! -z ${GIT_REMOTE_BRANCH} ]]; then - local ahead_behind_status=$(git rev-list --left-right --count \ - ${GIT_CURRENT_BRANCH}...${GIT_REMOTE_BRANCH}) - local commits_ahead=$(echo -n "$ahead_behind_status" | awk '{print $1}') - local commits_behind=$(echo -n "$ahead_behind_status" | awk '{print $2}') - - (( ${commits_behind} > 0 )) \ - && GIT_COMMITS_BEHIND="↓${commits_behind} " \ - && git_has_changes=1 - (( ${commits_ahead} > 0 )) \ - && GIT_COMMITS_AHEAD="↑${commits_ahead} " \ - && git_has_changes=1 - fi - GIT_COMMITS_STATUS="${GIT_COMMITS_AHEAD}${GIT_COMMITS_BEHIND}" - - if (( $git_has_changes )); then - (( ${staged_files} > 0 )) \ - && GIT_STAGED="+${staged_files} " - (( ${modified_files} > 0 )) \ - && GIT_MODIFIED="!${modified_files} " - (( ${deleted_files} > 0 )) \ - && GIT_DELETED="-${deleted_files} " - (( ${untracked_files} > 0 )) \ - && GIT_UNTRACKED="?${untracked_files}" - local fg_special=$'\e[0;33m' - else - local fg_special=$'\e[01;32m' - fi - - GIT_STATUS="${fg_special}" - GIT_STATUS+=" ${GIT_CURRENT_BRANCH} " - GIT_STATUS+="${GIT_COMMITS_STATUS}" - GIT_STATUS+="${GIT_MODIFIED}${GIT_STAGED}" - GIT_STATUS+="${GIT_DELETED}${GIT_UNTRACKED}" - GIT_STATUS+=$'\e[0m' - - # Remove trailing whitespace - GIT_STATUS="$(sed 's/[ ]+$//' <<<"$GIT_STATUS")" + typeset -g STATUS=("$modified" "$staged" "$deleted" "$untracked") + return 0 } -### -# Control script from here -# Globals: -# none -# Arguments: -# none -### -function main() { - sanitize || return 1 +function get_differences_between_remote_and_local() +{ + local local_branch="$1" + local remote_branch="$2" - parse_git_status + local differences="$(git rev-list --left-right --count $local_branch...$remote_branch)" + local commits_ahead=$(echo -n "$differences" | awk '{print $1}') + local commits_behind=$(echo -n "$differences" | awk '{print $2}') + + (( $commits_ahead > 0 )) \ + && local ahead="↑$commits_ahead" + (( $commits_behind > 0 )) \ + && local behind="↓$commits_behind" + + typeset -g REPLY="$ahead $behind" + return 0 +} + +function git_determine_color() +{ + for i in "$@"; do + if (( $i > 0 )); then + typeset -g REPLY=$'\e[93m' + return 0 + fi + done + typeset -g REPLY=$'\e[92m' + return 0 } main