changes to caching

This commit is contained in:
2025-11-23 15:17:39 +00:00
parent 919668af85
commit 6b5ef98fc6

View File

@@ -65,37 +65,78 @@ set_git_prompt_theme_icons() {
}
set_git_prompt_theme_icons
# Caching mechanism
# Caching mechanism (per-shell cache file)
GIT_CACHE_FILE="/tmp/git_prompt_cache.$$"
GIT_CACHE_EXPIRY=2 # seconds
# Internal state used for caching
GIT_STATE_HEAD=""
GIT_STATE_STATUS=""
GIT_STATE_STASH_LIST=""
GIT_STATE_FINGERPRINT=""
# Collect git state and build a fingerprint of the working tree
git_collect_state() {
# HEAD (commit hash)
GIT_STATE_HEAD=$(git rev-parse HEAD 2>/dev/null) || return 1
# Full status including branch / ahead / behind
GIT_STATE_STATUS=$(GIT_OPTIONAL_LOCKS=0 git status --porcelain --branch 2>/dev/null) || return 1
# Stash list (for stash count)
GIT_STATE_STASH_LIST=$(GIT_OPTIONAL_LOCKS=0 git stash list 2>/dev/null || true)
# Build fingerprint from head, status and stash list
if command -v sha1sum >/dev/null 2>&1; then
GIT_STATE_FINGERPRINT=$(
printf '%s\n%s\n%s\n' \
"$GIT_STATE_HEAD" \
"$GIT_STATE_STATUS" \
"$GIT_STATE_STASH_LIST" \
| sha1sum 2>/dev/null | awk '{print $1}'
)
else
# Fallback if sha1sum is missing (very rare on Ubuntu)
GIT_STATE_FINGERPRINT=$(printf '%s\n%s\n%s\n' "$GIT_STATE_HEAD" "$GIT_STATE_STATUS" "$GIT_STATE_STASH_LIST")
fi
return 0
}
actual_git_prompt_info_logic() {
git rev-parse --is-inside-work-tree &>/dev/null || return
# Require collected state
[[ -n "$GIT_STATE_STATUS" ]] || return
local branch
branch=$(git symbolic-ref --short HEAD 2>/dev/null || echo "(detached)")
local status
status=$(GIT_OPTIONAL_LOCKS=0 git status --porcelain --branch 2>/dev/null) || return
local status="$GIT_STATE_STATUS"
local stash_list="$GIT_STATE_STASH_LIST"
local staged conflicts changed untracked stashed is_clean has_remote
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 .)
stashed=$(grep -c . <<<"$stash_list")
local upstream
upstream=$(git rev-parse --abbrev-ref --symbolic-full-name "@{u}" 2>/dev/null)
[[ -n "$upstream" ]] && has_remote=1 || has_remote=0
# Parse the first status line to detect remote and ahead/behind
local first_line
first_line=${status%%$'\n'*}
local ahead=0 behind=0
if (( has_remote )); then
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}
local ahead=0
local behind=0
has_remote=0
if [[ "$first_line" == "## "* ]]; then
# If there's a tracking branch, the line will contain "..."
[[ "$first_line" == *"..."* ]] && has_remote=1
if [[ "$first_line" =~ ahead\ ([0-9]+) ]]; then
ahead=${BASH_REMATCH[1]}
fi
if [[ "$first_line" =~ behind\ ([0-9]+) ]]; then
behind=${BASH_REMATCH[1]}
fi
fi
is_clean=0
@@ -106,13 +147,13 @@ actual_git_prompt_info_logic() {
if [[ "$GIT_PROMPT_THEME" == "2" ]]; then
printf "\[\e[30;44m\]"
printf "\[\e[97;44m\] %s%s" "$BRANCH_ICON" "$branch"
((staged > 0)) && printf " %s%d" "$STAGED_ICON" "$staged"
((conflicts > 0)) && printf " %s%d" "$CONFLICT_ICON" "$conflicts"
((changed > 0)) && printf " %s%d" "$CHANGED_ICON" "$changed"
((untracked > 0)) && printf " %s%d" "$UNTRACKED_ICON" "$untracked"
((stashed > 0)) && printf " %s%d" "$STASHED_ICON" "$stashed"
((ahead > 0)) && printf " %s%d" "$AHEAD_ICON" "$ahead"
((behind > 0)) && printf " %s%d" "$BEHIND_ICON" "$behind"
((staged > 0)) && printf " %s%d" "$STAGED_ICON" "$staged"
((conflicts > 0)) && printf " %s%d" "$CONFLICT_ICON" "$conflicts"
((changed > 0)) && printf " %s%d" "$CHANGED_ICON" "$changed"
((untracked > 0)) && printf " %s%d" "$UNTRACKED_ICON" "$untracked"
((stashed > 0)) && printf " %s%d" "$STASHED_ICON" "$stashed"
((ahead > 0)) && printf " %s%d" "$AHEAD_ICON" "$ahead"
((behind > 0)) && printf " %s%d" "$BEHIND_ICON" "$behind"
((has_remote == 0)) && printf " %s" "$NO_REMOTE_ICON"
((is_clean)) && printf " %s" "$CLEAN_ICON" || printf " %s" "$DIRTY_ICON"
printf "\[\e[34;107m\]"
@@ -122,29 +163,29 @@ actual_git_prompt_info_logic() {
elif [[ "$GIT_PROMPT_THEME" == "3" ]]; then
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"
((conflicts > 0)) && printf " \e[38;5;196m%s%d\e[0m" "$CONFLICT_ICON" "$conflicts"
((changed > 0)) && printf " \e[38;5;69m%s%d\e[0m" "$CHANGED_ICON" "$changed"
((untracked > 0)) && printf " \e[38;5;41m%s%d\e[0m" "$UNTRACKED_ICON" "$untracked"
((stashed > 0)) && printf " \e[38;5;226m%s%d\e[0m" "$STASHED_ICON" "$stashed"
((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"
((staged > 0)) && printf " \e[38;5;196m%s%d\e[0m" "$STAGED_ICON" "$staged"
((conflicts > 0)) && printf " \e[38;5;196m%s%d\e[0m" "$CONFLICT_ICON" "$conflicts"
((changed > 0)) && printf " \e[38;5;69m%s%d\e[0m" "$CHANGED_ICON" "$changed"
((untracked > 0)) && printf " \e[38;5;41m%s%d\e[0m" "$UNTRACKED_ICON" "$untracked"
((stashed > 0)) && printf " \e[38;5;226m%s%d\e[0m" "$STASHED_ICON" "$stashed"
((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"
((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
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"
((conflicts > 0)) && printf " \e[38;5;196m%s%d\e[0m" "$CONFLICT_ICON" "$conflicts"
((changed > 0)) && printf " \e[38;5;69m%s%d\e[0m" "$CHANGED_ICON" "$changed"
((untracked > 0)) && printf " \e[38;5;41m%s%d\e[0m" "$UNTRACKED_ICON" "$untracked"
((stashed > 0)) && printf " \e[38;5;226m%s%d\e[0m" "$STASHED_ICON" "$stashed"
((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"
((is_clean)) && printf " \e[0;32m%s\e[0m" "$CLEAN_ICON" || printf " \e[38;5;196m%s\e[0m" "$DIRTY_ICON"
((staged > 0)) && printf " \e[38;5;196m%s%d\e[0m" "$STAGED_ICON" "$staged"
((conflicts > 0)) && printf " \e[38;5;196m%s%d\e[0m" "$CONFLICT_ICON" "$conflicts"
((changed > 0)) && printf " \e[38;5;69m%s%d\e[0m" "$CHANGED_ICON" "$changed"
((untracked > 0)) && printf " \e[38;5;41m%s%d\e[0m" "$UNTRACKED_ICON" "$untracked"
((stashed > 0)) && printf " \e[38;5;226m%s%d\e[0m" "$STASHED_ICON" "$stashed"
((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"
((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
}
@@ -152,18 +193,29 @@ actual_git_prompt_info_logic() {
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)
git_collect_state || return
if (( now - last_mod < GIT_CACHE_EXPIRY )); then
cat "$GIT_CACHE_FILE"
return
local fingerprint="$GIT_STATE_FINGERPRINT"
if [[ -f "$GIT_CACHE_FILE" ]]; then
local cached_fp
IFS= read -r cached_fp < "$GIT_CACHE_FILE"
if [[ -n "$cached_fp" && "$cached_fp" == "$fingerprint" ]]; then
# Fingerprint unchanged → reuse cached rendered prompt
sed '1d' "$GIT_CACHE_FILE"
return
fi
fi
# Recompute prompt and refresh cache
local output
output=$(actual_git_prompt_info_logic)
echo "$output" > "$GIT_CACHE_FILE"
output=$(actual_git_prompt_info_logic) || return
{
echo "$fingerprint"
echo "$output"
} > "$GIT_CACHE_FILE"
echo "$output"
}