summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xgit-sonar114
1 files changed, 59 insertions, 55 deletions
diff --git a/git-sonar b/git-sonar
index 7d71606..4da43f8 100755
--- a/git-sonar
+++ b/git-sonar
@@ -83,6 +83,7 @@ FETCH_TIME="${GIT_SONAR_FETCH_TIME:-"300"}"
ALERT_ICON="${GIT_SONAR_ALERT_ICON:-"${COLOR_YELLOW}⚡"}"
STASH_ICON="${GIT_SONAR_STASH_ICON:-"${COLOR_YELLOW}≡"}"
BRANCH_COLOR="${GIT_SONAR_BRANCH_COLOR:-"$COLOR_DEF"}"
+STATUS_SEP="${GIT_SONAR_STATUS_SEPARATOR:-" "}"
AHEAD_ICON="${GIT_SONAR_AHEAD_ICON:-"${COLOR_GREEN}↑"}" # "←"
BEHIND_ICON="${GIT_SONAR_BEHIND_ICON:-"${COLOR_RED}↓"}" # "→"
@@ -94,13 +95,10 @@ UNMERGED_COLOR="${GIT_SONAR_UNMERGED_COLOR:-"$COLOR_YELLOW"}"
UNTRACKED_COLOR="${GIT_SONAR_UNTRACKED_COLOR:-"$COLOR_WHITE"}"
PROMPT_COLOR="${GIT_SONAR_PROMPT_COLOR:-"$COLOR_GRAY"}"
-PROMPT_FORMAT="${GIT_SONAR_PROMPT_FORMAT:-" ${PROMPT_COLOR}git:(${COLOR_DEF}%{alert}%{remote: }%{branch}%{ :local}${PROMPT_COLOR})${COLOR_DEF}%{ :stash}%{ :staged}%{ :unmerged}%{ :unstaged}%{ :untracked}"}"
+PROMPT_FORMAT="${GIT_SONAR_PROMPT_FORMAT:-" ${PROMPT_COLOR}git:(${COLOR_DEF}%{alert}%{remote: }%{branch}%{ :local}${PROMPT_COLOR})${COLOR_DEF}%{ :stash}%{ :status}"}"
-# Gather current git status and branch information. git porcelain status can
-# be especially expensive to compute, so bypass it if the prompt disables status
-# information.
-[ -n "$opt_status" ] && git_status="$(git status --porcelain 2>/dev/null)" || git_status=""
-upstream_name="$(git rev-parse --abbrev-ref --symbolic-full-name '@{upstream}' 2>/dev/null)"
+# Gather information about the current git branch.
+upstream_name="$(git rev-parse --abbrev-ref '@{upstream}' 2>/dev/null)"
branch_name="$(git symbolic-ref --short HEAD 2>/dev/null)"
commit_hash="$(git rev-parse --short HEAD 2>/dev/null)"
@@ -116,18 +114,6 @@ determine_default_branch() {
done
}
-line_count() {
- # macos 'wc' produces odd formatting (extra spaces)
- # The grep is present to deal with this, filter out cases where the count
- # is zero, and provide a return value (true if count is non-zero).
- wc -l 2>/dev/null | grep -oE '[1-9][0-9]*'
-}
-
-status_count() {
- # Use a sed transform to prevent unmerged paths from being miscounted
- echo "$git_status" | sed -nE "s/^AA /AU /;s/^DD /DU /;/${1}/p" | line_count
-}
-
print_commit_range() {
if [ -n "$1" ] && [ -n "$2" ]; then
ahead="$(git rev-list --count "${1}..${2}" 2>/dev/null)" || ahead="0"
@@ -173,65 +159,86 @@ element_local() {
element_stash() {
if [ -n "$opt_stash" ]; then
- if cnt="$(git stash list | line_count)"; then
+ cnt="$(git rev-list --walk-reflogs --ignore-missing --count refs/stash)"
+ if [ "$cnt" -ne 0 ]; then
printf '%s%b%b' "$cnt" "$STASH_ICON" "$COLOR_DEF"
fi
fi
}
-element_staged() {
+element_status() {
if [ -n "$opt_status" ]; then
+ # git status is the most expensive subprocess we call, so place it here
+ # to bypass it if $opt_status is "false". The output is filtered
+ # through sed to prevent certain unmerged paths from being double
+ # counted as staged/unstaged ("AA"/"DD").
+ git_status="$(\
+ git status --porcelain 2>/dev/null \
+ | sed 's/^AA /AU /;s/^DD /DU /' \
+ )"
+
+ gs=""
+ st_sep="$STATUS_SEP"
+ um_sep="$STATUS_SEP"
+ us_sep="$STATUS_SEP"
+ ut_sep="$STATUS_SEP"
+
+ # See "man 1 git-status" sections "Short Format" and "Porcelain Format
+ # Version 1" for an explanation of these status indicators.
+
+ # Staged
for x in A M R C D T; do
- if cnt="$(status_count "^${x}[^U] ")"; then
- printf '%s%b%s%b' "$cnt" "$STAGED_COLOR" "$x" "$COLOR_DEF"
+ if cnt="$(echo "$git_status" | grep -cE "^${x}[^U] ")"; then
+ gs="$(printf '%b%b%s%b%s%b' \
+ "$gs" "$st_sep" "$cnt" "$STAGED_COLOR" "$x" "$COLOR_DEF" \
+ )"
+ st_sep=""
fi
done
- fi
-}
-element_unstaged() {
- if [ -n "$opt_status" ]; then
- for x in M D T; do
- if cnt="$(status_count "^[^U]${x} ")"; then
- printf '%s%b%s%b' "$cnt" "$UNSTAGED_COLOR" "$x" "$COLOR_DEF"
+ # Unmerged, conflicted
+ for x in A U D; do
+ if cnt="$(echo "$git_status" | grep -cE "^(U${x}|${x}U) ")"; then
+ gs="$(printf '%b%b%s%b%s%b' \
+ "$gs" "$um_sep" "$cnt" "$UNMERGED_COLOR" "$x" "$COLOR_DEF" \
+ )"
+ um_sep=""
fi
done
- fi
-}
-element_unmerged() {
- if [ -n "$opt_status" ]; then
- for x in A U D; do
- if cnt="$(status_count "^(U${x}|${x}U) ")"; then
- printf '%s%b%s%b' "$cnt" "$UNMERGED_COLOR" "$x" "$COLOR_DEF"
+ # Unstaged
+ for x in M D T; do # R C omitted
+ if cnt="$(echo "$git_status" | grep -cE "^[^U]${x} ")"; then
+ gs="$(printf '%b%b%s%b%s%b' \
+ "$gs" "$us_sep" "$cnt" "$UNSTAGED_COLOR" "$x" "$COLOR_DEF" \
+ )"
+ us_sep=""
fi
done
- fi
-}
-element_untracked() {
- if [ -n "$opt_status" ]; then
- if cnt="$(status_count "^\?\? ")"; then
- printf '%s%b?%b' "$cnt" "$UNTRACKED_COLOR" "$COLOR_DEF"
+ # Untracked
+ if cnt="$(echo "$git_status" | grep -cE "^\?\? ")"; then
+ gs="$(printf '%b%b%s%b?%b' \
+ "$gs" "$ut_sep" "$cnt" "$UNTRACKED_COLOR" "$COLOR_DEF" \
+ )"
+ ut_sep=""
fi
+
+ printf '%b' "${gs#"$STATUS_SEP"}"
fi
}
# Main functions
-IF_PRE="%\{([^%{}]{1,}:){0,1}"
-IF_POST="(:[^%{}]{1,}){0,1}\}"
SED_PRE="%{\(\([^%^{^}]*\)\:\)\{0,1\}"
SED_POST="\(\:\([^%^{^}]*\)\)\{0,1\}}"
prepare_element() {
- if echo "$PROMPT_FORMAT" | grep -qE "${IF_PRE}${1}${IF_POST}"; then
- result="$($2 | sed -e 's/\//\\\//g')"
- if [ -n "$result" ]; then
- printf '%b' "s/${SED_PRE}${1}${SED_POST}/\\\\2${result}\\\\4/"
- else
- printf '%b' "s/${SED_PRE}${1}${SED_POST}//"
- fi
+ result="$($2 | sed 's/\//\\\//g')"
+ if [ -n "$result" ]; then
+ printf '%b' "s/${SED_PRE}${1}${SED_POST}/\\\\2${result}\\\\4/"
+ else
+ printf '%b' "s/${SED_PRE}${1}${SED_POST}//"
fi
}
@@ -255,7 +262,4 @@ printf '%b' "$PROMPT_FORMAT" | sed \
-e "$(prepare_element remote element_remote)" \
-e "$(prepare_element local element_local)" \
-e "$(prepare_element stash element_stash)" \
- -e "$(prepare_element staged element_staged)" \
- -e "$(prepare_element unstaged element_unstaged)" \
- -e "$(prepare_element unmerged element_unmerged)" \
- -e "$(prepare_element untracked element_untracked)"
+ -e "$(prepare_element status element_status)"