|
zmodload zsh/system |
|
typeset -g _gitstatus_fd _gitstatus_child_pid |
|
|
|
_gitstatus_check() { |
|
emulate -L zsh |
|
|
|
read -d '' script <<- 'EOF' |
|
BEGIN { |
|
conflicted = 0 |
|
deleted = 0 |
|
renamed = 0 |
|
modified = 0 |
|
staged = 0 |
|
typechanged = 0 |
|
untracked = 0 |
|
} |
|
END { |
|
print "conflicted", conflicted |
|
print "deleted", deleted |
|
print "renamed", renamed |
|
print "modified", modified |
|
print "staged", staged |
|
print "typechanged", typechanged |
|
print "untracked", untracked |
|
print "ahead", ahead |
|
print "behind", behind |
|
print "branch", branch |
|
} |
|
function handle_file() { |
|
fst = substr($2, 1, 1) |
|
snd = substr($2, 2, 1) |
|
|
|
if (snd == "D") { |
|
deleted += 1 |
|
} |
|
|
|
if (snd == "M" || snd == "A") { |
|
modified += 1 |
|
} |
|
|
|
if (fst == "M" || fst == "A" || fst == "T" || fst == "D") { |
|
staged += 1 |
|
} |
|
|
|
if (snd == "T") { |
|
typechanged += 1 |
|
} |
|
} |
|
{ |
|
if ($1 == "#") { |
|
# header |
|
if ($2 == "branch.ab") { |
|
# ahead-behind |
|
ahead = strtonum(substr($3,2)) |
|
behind = strtonum(substr($4,2)) |
|
} else if ($2 == "branch.oid") { |
|
commit = substr($3,1,7) |
|
} else if ($2 == "branch.head") { |
|
if ($3 == "(detached)") { |
|
branch = commit |
|
print "head_state", "detached" |
|
} else { |
|
branch = $3 |
|
print "head_state", "branch" |
|
} |
|
} else if ($2 == "branch.upstream") { |
|
print "remote_branch", $3 |
|
} else if ($2 == "stash") { |
|
print "stashed", $3 |
|
} |
|
} else if ($1 == "?") { |
|
# untracked file |
|
untracked += 1 |
|
} else if ($1 == "!") { |
|
# ignored file |
|
} else if ($1 == "1") { |
|
# normal file |
|
handle_file() |
|
} else if ($1 == "2") { |
|
# rename/copy |
|
renamed += 1 |
|
handle_file() |
|
} else if ($1 == "u") { |
|
# conflicting |
|
conflicted += 1 |
|
} |
|
} |
|
EOF |
|
git status --porcelain=v2 --branch --show-stash --ahead-behind | gawk -v "OFS==" -v "ORS=;" $script - |
|
} |
|
|
|
_gitstatus_callback() { |
|
emulate -L zsh |
|
|
|
local conflicted deleted renamed modified staged typechanged untracked |
|
local ahead behind branch remote_branch stashed head_state |
|
|
|
if [[ -z "$2" || "$2" == "hup" ]]; then |
|
IFS='' read -rd '' -u $1 result |
|
|
|
eval $result |
|
|
|
unset _gitstatus_conflicted _gitstatus_deleted _gitstatus_renamed |
|
unset _gitstatus_modified _gitstatus_staged _gitstatus_typechanged |
|
unset _gitstatus_untracked _gitstatus_ahead _gitstatus_behind |
|
unset _gitstatus_stashed _gitstatus_head_state |
|
|
|
if ((conflicted != 0)); then |
|
_gitstatus_conflicted=$conflicted |
|
fi |
|
if ((deleted != 0)); then |
|
_gitstatus_deleted=$deleted |
|
fi |
|
if ((renamed != 0)); then |
|
_gitstatus_renamed=$renamed |
|
fi |
|
if ((modified != 0)); then |
|
_gitstatus_modified=$modified |
|
fi |
|
if ((staged != 0)); then |
|
_gitstatus_staged=$staged |
|
fi |
|
if ((typechanged != 0)); then |
|
_gitstatus_typechanged=$typechanged |
|
fi |
|
if ((untracked != 0)); then |
|
_gitstatus_untracked=$untracked |
|
fi |
|
if ((ahead != 0)); then |
|
_gitstatus_ahead=$ahead |
|
fi |
|
if ((behind != 0)); then |
|
_gitstatus_behind=$behind |
|
fi |
|
_gitstatus_branch=$branch |
|
_gitstatus_head_state=$head_state |
|
_gitstatus_remote_branch=$remote_branch |
|
_gitstatus_stashed=$stashed |
|
|
|
p10k display -r |
|
|
|
builtin exec {1}<&- |
|
else |
|
echo "command failed with error $2" 1>&2 |
|
fi |
|
|
|
zle -F "$1" |
|
_gitstatus_fd= |
|
_gitstatus_child_pid= |
|
} |
|
|
|
prompt_gitstatus() { |
|
emulate -L zsh |
|
|
|
(($+commands[git])) || return |
|
|
|
local gitDir="$(git rev-parse --git-dir 2> /dev/null)" |
|
[[ $? != 0 || -z $gitDir ]] && return |
|
|
|
# If POWERLEVEL9K_VCS_DISABLED_WORKDIR_PATTERN (e.g., "~" or a glob) matches $PWD, return |
|
if [[ -n ${POWERLEVEL9K_VCS_DISABLED_WORKDIR_PATTERN-} ]]; then |
|
# Expand a leading ~ to $HOME, then treat the result as a glob pattern |
|
if [[ ${${gitDir:A}:h} == ${~${POWERLEVEL9K_VCS_DISABLED_WORKDIR_PATTERN/#\~/$HOME}} ]]; then |
|
return |
|
fi |
|
fi |
|
|
|
|
|
if [[ -n "$_gitstatus_fd" ]] && { true <&$_gitstatus_fd } 2>/dev/null; then |
|
exec {_gitstatus_fd}>&- |
|
zle -F $_gitstatus_fd |
|
|
|
if [[ -n "$_gitstatus_child_pid" ]]; then |
|
if [[ -o monitor ]]; then |
|
kill -TERM -$_gitstatus_child_pid 2>/dev/null |
|
else |
|
kill -TERM $_gitstatus_child_pid 2>/dev/null |
|
fi |
|
fi |
|
fi |
|
|
|
exec {_gitstatus_fd}< <( |
|
echo $sysparams[pid] |
|
_gitstatus_check |
|
) |
|
command true |
|
read _gitstatus_child_pid <& $_gitstatus_fd |
|
|
|
zle -F "$_gitstatus_fd" _gitstatus_callback |
|
|
|
|
|
p10k segment -s BRANCH -c '${(M)_gitstatus_head_state:#branch}' -f green -i "%fon" -et '$_gitstatus_branch' |
|
p10k segment -s DETACHED -c '${(M)_gitstatus_head_state:#detached}' -et '%f@%F{green}$_gitstatus_branch' |
|
p10k segment -c '$_gitstatus_remote_branch' -f green -et '⇄ $_gitstatus_remote_branch' |
|
|
|
if [[ -f $gitDir/rebase-apply/applying ]]; then |
|
p10k segment -f red -t "am" |
|
elif [[ -f $gitDir/rebase-apply/rebasing ]]; then |
|
p10k segment -f red -t "rebase" |
|
elif [[ -d $gitDir/rebase-apply ]]; then |
|
p10k segment -f red -t "am/rebase" |
|
elif [[ -f $gitDir/rebase-merge/interactive ]]; then |
|
p10k segment -f red -t "rebase-i" |
|
elif [[ -d $gitDir/rebase-merge ]]; then |
|
p10k segment -f red -t "rebase" |
|
elif [[ -f $gitDir/CHERRY_PICK_HEAD ]]; then |
|
p10k segment -f red -t "cherry-pick" |
|
elif [[ -f $gitDir/MERGE_HEAD ]]; then |
|
p10k segment -f red -t "merge" |
|
elif [[ -f $gitDir/BISECT_LOG ]]; then |
|
p10k segment -f red -t "bisect" |
|
elif [[ -f $gitDir/REVERT_HEAD ]]; then |
|
p10k segment -f red -t "revert" |
|
fi |
|
|
|
p10k segment -c '$_gitstatus_ahead' -f green -et '⇡$_gitstatus_ahead' |
|
p10k segment -c '$_gitstatus_behind' -f green -et '⇣$_gitstatus_behind' |
|
p10k segment -c '$_gitstatus_conflicted' -f red -et '~$_gitstatus_conflicted' |
|
p10k segment -c '$_gitstatus_stashed' -f green -et '*$_gitstatus_stashed' |
|
p10k segment -c '$_gitstatus_staged' -f yellow -et '+$_gitstatus_staged' |
|
p10k segment -c '$_gitstatus_renamed' -f cyan -et '↠$_gitstatus_renamed' |
|
p10k segment -c '$_gitstatus_deleted' -f red -et '×$_gitstatus_deleted' |
|
p10k segment -c '$_gitstatus_modified' -f yellow -et '!$_gitstatus_modified' |
|
p10k segment -c '$_gitstatus_untracked' -f blue -et '?$_gitstatus_untracked' |
|
} |
Nice, it speeds-up things.
One addition is to use
POWERLEVEL9K_VCS_DISABLED_WORKDIR_PATTERNwhich will make starting prompt in git-managed home directory much faster.