From 13c702964c0287059a75eaec98cd71de51f4f19c Mon Sep 17 00:00:00 2001 From: Ilia Burtsev Date: Sat, 24 May 2025 13:39:17 +0300 Subject: [PATCH] fix(async): ensure `git_prompt_status` can be registered (#13134) --- lib/git.zsh | 198 ++++++++++++++++++++++++++-------------------------- 1 file changed, 99 insertions(+), 99 deletions(-) diff --git a/lib/git.zsh b/lib/git.zsh index a1b4d1587..f4d4229cb 100644 --- a/lib/git.zsh +++ b/lib/git.zsh @@ -39,6 +39,105 @@ function _omz_git_prompt_info() { echo "${ZSH_THEME_GIT_PROMPT_PREFIX}${ref:gs/%/%%}${upstream:gs/%/%%}$(parse_git_dirty)${ZSH_THEME_GIT_PROMPT_SUFFIX}" } +function _omz_git_prompt_status() { + [[ "$(__git_prompt_git config --get oh-my-zsh.hide-status 2>/dev/null)" = 1 ]] && return + + # Maps a git status prefix to an internal constant + # This cannot use the prompt constants, as they may be empty + local -A prefix_constant_map + prefix_constant_map=( + '\?\? ' 'UNTRACKED' + 'A ' 'ADDED' + 'M ' 'MODIFIED' + 'MM ' 'MODIFIED' + ' M ' 'MODIFIED' + 'AM ' 'MODIFIED' + ' T ' 'MODIFIED' + 'R ' 'RENAMED' + ' D ' 'DELETED' + 'D ' 'DELETED' + 'UU ' 'UNMERGED' + 'ahead' 'AHEAD' + 'behind' 'BEHIND' + 'diverged' 'DIVERGED' + 'stashed' 'STASHED' + ) + + # Maps the internal constant to the prompt theme + local -A constant_prompt_map + constant_prompt_map=( + 'UNTRACKED' "$ZSH_THEME_GIT_PROMPT_UNTRACKED" + 'ADDED' "$ZSH_THEME_GIT_PROMPT_ADDED" + 'MODIFIED' "$ZSH_THEME_GIT_PROMPT_MODIFIED" + 'RENAMED' "$ZSH_THEME_GIT_PROMPT_RENAMED" + 'DELETED' "$ZSH_THEME_GIT_PROMPT_DELETED" + 'UNMERGED' "$ZSH_THEME_GIT_PROMPT_UNMERGED" + 'AHEAD' "$ZSH_THEME_GIT_PROMPT_AHEAD" + 'BEHIND' "$ZSH_THEME_GIT_PROMPT_BEHIND" + 'DIVERGED' "$ZSH_THEME_GIT_PROMPT_DIVERGED" + 'STASHED' "$ZSH_THEME_GIT_PROMPT_STASHED" + ) + + # The order that the prompt displays should be added to the prompt + local status_constants + status_constants=( + UNTRACKED ADDED MODIFIED RENAMED DELETED + STASHED UNMERGED AHEAD BEHIND DIVERGED + ) + + local status_text + status_text="$(__git_prompt_git status --porcelain -b 2> /dev/null)" + + # Don't continue on a catastrophic failure + if [[ $? -eq 128 ]]; then + return 1 + fi + + # A lookup table of each git status encountered + local -A statuses_seen + + if __git_prompt_git rev-parse --verify refs/stash &>/dev/null; then + statuses_seen[STASHED]=1 + fi + + local status_lines + status_lines=("${(@f)${status_text}}") + + # If the tracking line exists, get and parse it + if [[ "$status_lines[1]" =~ "^## [^ ]+ \[(.*)\]" ]]; then + local branch_statuses + branch_statuses=("${(@s/,/)match}") + for branch_status in $branch_statuses; do + if [[ ! $branch_status =~ "(behind|diverged|ahead) ([0-9]+)?" ]]; then + continue + fi + local last_parsed_status=$prefix_constant_map[$match[1]] + statuses_seen[$last_parsed_status]=$match[2] + done + fi + + # For each status prefix, do a regex comparison + for status_prefix in ${(k)prefix_constant_map}; do + local status_constant="${prefix_constant_map[$status_prefix]}" + local status_regex=$'(^|\n)'"$status_prefix" + + if [[ "$status_text" =~ $status_regex ]]; then + statuses_seen[$status_constant]=1 + fi + done + + # Display the seen statuses in the order specified + local status_prompt + for status_constant in $status_constants; do + if (( ${+statuses_seen[$status_constant]} )); then + local next_display=$constant_prompt_map[$status_constant] + status_prompt="$next_display$status_prompt" + fi + done + + echo $status_prompt +} + # Use async version if setting is enabled, or unset but zsh version is at least 5.0.6. # This avoids async prompt issues caused by previous zsh versions: # - https://github.com/ohmyzsh/ohmyzsh/issues/12331 @@ -246,105 +345,6 @@ function git_prompt_long_sha() { SHA=$(__git_prompt_git rev-parse HEAD 2> /dev/null) && echo "$ZSH_THEME_GIT_PROMPT_SHA_BEFORE$SHA$ZSH_THEME_GIT_PROMPT_SHA_AFTER" } -function _omz_git_prompt_status() { - [[ "$(__git_prompt_git config --get oh-my-zsh.hide-status 2>/dev/null)" = 1 ]] && return - - # Maps a git status prefix to an internal constant - # This cannot use the prompt constants, as they may be empty - local -A prefix_constant_map - prefix_constant_map=( - '\?\? ' 'UNTRACKED' - 'A ' 'ADDED' - 'M ' 'MODIFIED' - 'MM ' 'MODIFIED' - ' M ' 'MODIFIED' - 'AM ' 'MODIFIED' - ' T ' 'MODIFIED' - 'R ' 'RENAMED' - ' D ' 'DELETED' - 'D ' 'DELETED' - 'UU ' 'UNMERGED' - 'ahead' 'AHEAD' - 'behind' 'BEHIND' - 'diverged' 'DIVERGED' - 'stashed' 'STASHED' - ) - - # Maps the internal constant to the prompt theme - local -A constant_prompt_map - constant_prompt_map=( - 'UNTRACKED' "$ZSH_THEME_GIT_PROMPT_UNTRACKED" - 'ADDED' "$ZSH_THEME_GIT_PROMPT_ADDED" - 'MODIFIED' "$ZSH_THEME_GIT_PROMPT_MODIFIED" - 'RENAMED' "$ZSH_THEME_GIT_PROMPT_RENAMED" - 'DELETED' "$ZSH_THEME_GIT_PROMPT_DELETED" - 'UNMERGED' "$ZSH_THEME_GIT_PROMPT_UNMERGED" - 'AHEAD' "$ZSH_THEME_GIT_PROMPT_AHEAD" - 'BEHIND' "$ZSH_THEME_GIT_PROMPT_BEHIND" - 'DIVERGED' "$ZSH_THEME_GIT_PROMPT_DIVERGED" - 'STASHED' "$ZSH_THEME_GIT_PROMPT_STASHED" - ) - - # The order that the prompt displays should be added to the prompt - local status_constants - status_constants=( - UNTRACKED ADDED MODIFIED RENAMED DELETED - STASHED UNMERGED AHEAD BEHIND DIVERGED - ) - - local status_text - status_text="$(__git_prompt_git status --porcelain -b 2> /dev/null)" - - # Don't continue on a catastrophic failure - if [[ $? -eq 128 ]]; then - return 1 - fi - - # A lookup table of each git status encountered - local -A statuses_seen - - if __git_prompt_git rev-parse --verify refs/stash &>/dev/null; then - statuses_seen[STASHED]=1 - fi - - local status_lines - status_lines=("${(@f)${status_text}}") - - # If the tracking line exists, get and parse it - if [[ "$status_lines[1]" =~ "^## [^ ]+ \[(.*)\]" ]]; then - local branch_statuses - branch_statuses=("${(@s/,/)match}") - for branch_status in $branch_statuses; do - if [[ ! $branch_status =~ "(behind|diverged|ahead) ([0-9]+)?" ]]; then - continue - fi - local last_parsed_status=$prefix_constant_map[$match[1]] - statuses_seen[$last_parsed_status]=$match[2] - done - fi - - # For each status prefix, do a regex comparison - for status_prefix in ${(k)prefix_constant_map}; do - local status_constant="${prefix_constant_map[$status_prefix]}" - local status_regex=$'(^|\n)'"$status_prefix" - - if [[ "$status_text" =~ $status_regex ]]; then - statuses_seen[$status_constant]=1 - fi - done - - # Display the seen statuses in the order specified - local status_prompt - for status_constant in $status_constants; do - if (( ${+statuses_seen[$status_constant]} )); then - local next_display=$constant_prompt_map[$status_constant] - status_prompt="$next_display$status_prompt" - fi - done - - echo $status_prompt -} - # Outputs the name of the current user # Usage example: $(git_current_user_name) function git_current_user_name() {