diff --git a/bash-git-prompt b/bash-git-prompt index f6c164e..30465da 100644 --- a/bash-git-prompt +++ b/bash-git-prompt @@ -5,7 +5,7 @@ # Default to theme 1 if not set GIT_PROMPT_THEME="${GIT_PROMPT_THEME:-1}" -# Define all 6 themes +# Define theme icons set_git_prompt_theme_icons() { case "$GIT_PROMPT_THEME" in 2|3) @@ -62,40 +62,39 @@ set_git_prompt_theme_icons() { ;; esac } - -# Initialize icons set_git_prompt_theme_icons -# Git prompt logic -git_prompt_info() { +# Caching mechanism +GIT_CACHE_FILE="/tmp/git_prompt_cache.$$" +GIT_CACHE_EXPIRY=2 # seconds + +actual_git_prompt_info_logic() { git rev-parse --is-inside-work-tree &>/dev/null || return local branch branch=$(git symbolic-ref --short HEAD 2>/dev/null || echo "(detached)") local status - status=$(git status --porcelain=2 --branch 2>/dev/null) || return + status=$(GIT_OPTIONAL_LOCKS=0 git status --porcelain --branch 2>/dev/null) || return local staged conflicts changed untracked stashed is_clean has_remote - staged=$(grep -cE '^1 [ADMRT]' <<<"$status") - conflicts=$(grep -cE '^u ' <<<"$status") - changed=$(grep -cE '^1 .[MD]' <<<"$status") - untracked=$(grep -cE '^\? ' <<<"$status") - stashed=$(git stash list 2>/dev/null | wc -l | tr -d ' ') + staged=$(grep -cE '^[AMDR] ' <<<"$status") + conflicts=$(grep -cE '^UU ' <<<"$status") + changed=$(grep -cE '^.[MD] ' <<<"$status") + untracked=$(grep -cE '^\?\? ' <<<"$status") + stashed=$(GIT_OPTIONAL_LOCKS=0 git stash list 2>/dev/null | grep -c .) local upstream upstream=$(git rev-parse --abbrev-ref --symbolic-full-name "@{u}" 2>/dev/null) - if [[ -n "$upstream" ]]; then - has_remote=1 - git fetch --quiet & disown - else - has_remote=0 - fi + [[ -n "$upstream" ]] && has_remote=1 || has_remote=0 local ahead=0 behind=0 if (( has_remote )); then - ahead=$(git rev-list --left-right --count "$upstream...HEAD" 2>/dev/null | awk '{print $2}') - behind=$(git rev-list --left-right --count "$upstream...HEAD" 2>/dev/null | awk '{print $1}') + local counts + counts=$(git rev-list --left-right --count "${upstream}...HEAD" 2>/dev/null | tr -s '[:space:]' ' ') + read -r behind ahead <<< "$counts" + ahead=${ahead:-0} + behind=${behind:-0} fi is_clean=0 @@ -104,7 +103,6 @@ git_prompt_info() { fi if [[ "$GIT_PROMPT_THEME" == "2" ]]; then - # Powerline Theme 2 printf "\[\e[30;44m\]" printf "\[\e[97;44m\] %s%s" "$BRANCH_ICON" "$branch" ((staged > 0)) && printf " %s%d" "$STAGED_ICON" "$staged" @@ -115,18 +113,12 @@ git_prompt_info() { ((ahead > 0)) && printf " %s%d" "$AHEAD_ICON" "$ahead" ((behind > 0)) && printf " %s%d" "$BEHIND_ICON" "$behind" ((has_remote == 0)) && printf " %s" "$NO_REMOTE_ICON" - if (( is_clean )); then - printf " %s" "$CLEAN_ICON" - else - printf " %s" "$DIRTY_ICON" - fi + ((is_clean)) && printf " %s" "$CLEAN_ICON" || printf " %s" "$DIRTY_ICON" printf "\[\e[34;107m\]" printf "\[\e[30;107m\] \w" printf "\[\e[97;49m\]" printf "\[\e[0m\]" - elif [[ "$GIT_PROMPT_THEME" == "3" ]]; then - # Two-line theme: git info in brackets, directory outside (in gold) printf "\n\[\e[0;37m\]┌──[\e[0m" printf "\e[38;5;117m%s%s\e[0m" "$BRANCH_ICON" "$branch" ((staged > 0)) && printf " \e[38;5;196m%s%d\e[0m" "$STAGED_ICON" "$staged" @@ -137,17 +129,10 @@ git_prompt_info() { ((ahead > 0)) && printf " \e[0;37m%s%d\e[0m" "$AHEAD_ICON" "$ahead" ((behind > 0)) && printf " \e[0;37m%s%d\e[0m" "$BEHIND_ICON" "$behind" ((has_remote == 0)) && printf " \e[38;5;250m%s\e[0m" "$NO_REMOTE_ICON" - if (( is_clean )); then - printf " \e[0;32m%s\e[0m" "$CLEAN_ICON" - else - printf " \e[38;5;196m%s\e[0m" "$DIRTY_ICON" - fi - printf "\e[0;37m]\e[0m" - printf " \[\e[38;5;178m\]\w\[\e[0m\]" + ((is_clean)) && printf " \e[0;32m%s\e[0m" "$CLEAN_ICON" || printf " \e[38;5;196m%s\e[0m" "$DIRTY_ICON" + printf "\e[0;37m]\e[0m \[\e[38;5;178m\]\w\[\e[0m\]" printf "\n\[\e[0;37m\]└──\[\e[0m\]" - else - # Default bracket theme printf "\e[0;37m[\e[0m" printf "\e[38;5;117m%s%s\e[0m" "$BRANCH_ICON" "$branch" ((staged > 0)) && printf " \e[38;5;196m%s%d\e[0m" "$STAGED_ICON" "$staged" @@ -158,16 +143,29 @@ git_prompt_info() { ((ahead > 0)) && printf " \e[0;37m%s%d\e[0m" "$AHEAD_ICON" "$ahead" ((behind > 0)) && printf " \e[0;37m%s%d\e[0m" "$BEHIND_ICON" "$behind" ((has_remote == 0)) && printf " \e[38;5;250m%s\e[0m" "$NO_REMOTE_ICON" - if (( is_clean )); then - printf " \e[0;32m%s\e[0m" "$CLEAN_ICON" - else - printf " \e[38;5;196m%s\e[0m" "$DIRTY_ICON" - fi + ((is_clean)) && printf " \e[0;32m%s\e[0m" "$CLEAN_ICON" || printf " \e[38;5;196m%s\e[0m" "$DIRTY_ICON" printf "\e[0;37m]\e[0m" fi } -# Auto-updating prompt +git_prompt_info() { + git rev-parse --is-inside-work-tree &>/dev/null || return + + local now=$(date +%s) + local last_mod=0 + [[ -f "$GIT_CACHE_FILE" ]] && last_mod=$(stat -c %Y "$GIT_CACHE_FILE" 2>/dev/null || echo 0) + + if (( now - last_mod < GIT_CACHE_EXPIRY )); then + cat "$GIT_CACHE_FILE" + return + fi + + local output + output=$(actual_git_prompt_info_logic) + echo "$output" > "$GIT_CACHE_FILE" + echo "$output" +} + update_git_prompt() { local PROMPT_CHAR='$' [[ $EUID -eq 0 ]] && PROMPT_CHAR='#' @@ -188,7 +186,6 @@ update_git_prompt() { PROMPT_COMMAND=update_git_prompt -# Theme switch command gpchange() { local theme="${1:-}" if [[ "$theme" =~ ^[1-5]$ ]]; then