zsh/prompt_fresh_setup

174 lines
4.9 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

prompt_fresh_setup() {
compile_git_prompt
autoload -U add-zsh-hook
add-zsh-hook precmd fresh_precmd
if [ "$USERNAME" = "root" ]; then
local user="%{%F{9}%}%n%{%f%}"
else
local user="%{%F{35}%}%n%{%f%}"
fi
if [ "$SSH_CONNECTION" != "" ]; then
local user="%{%F{35}%}$user%{%f%}@%{%F{244}%}%M%{%f%}"
fi
local length=`visible_length "$user"`
PS1="«$user» "
PS2="${(l:$length + 1:: :)}» "
# TODO: RPS1
prompt_opts=(cr percent sp subst)
}
prompt_cleanup() {
if [ -f ~/.cache/zsh/git-prompt ]; then rm ~/.cache/zsh/git-prompt; fi
}
fresh_precmd() {
# First get the last commands exit code before doing anything
local exit_code=$?
# Construct the time and directory portions of the prompt
local time_stamp="%{%F{244}%}%D{%H:%M:%S}%{%f%}"
local directory="%{%F{37}%}%~%{%f%}"
# Check we are in a git repository
if `git rev-parse --git-dir > /dev/null 2>&1`; then
# Get git branch name & exit early if not found
local branch="`git symbolic-ref HEAD 2> /dev/null`"
if [ "" = "$branch" ]; then
local branch="`git rev-parse --abbrev-ref HEAD`"
if [ "HEAD" = "$branch" ]; then
local branch="`git rev-parse --short $branch`"
fi
fi
if [ "$branch" != "" ]; then
local branch=${branch#refs/heads/}
# Get the number of commits ahead/behind from the remote branch
local remote="`git config branch.$branch.remote 2> /dev/null`"
if [ "" != "remote" ]; then
local branches="refs/remotes/$remote/$branch...HEAD"
local nahead=`git rev-list --right-only $branches --count 2> /dev/null`
if [ "0" -ne "$nahead" ]; then local ahead="$nahead"; fi
local nbehind=`git rev-list --left-only $branches --count 2> /dev/null`
if [ "0" -ne "$nbehind" ]; then local behind="$nbehind"; fi
fi
# Construct the git prompt
local git="%{%F{66}%}$branch%{%f%}$ahead$behind "
if [ -f ~/.cache/zsh/git-prompt ]; then
# Get the change counts from git-prompt
local counts=(`~/.cache/zsh/git-prompt`)
# Parse the results from git-prompt
if [ 0 -eq ${#counts[@]} ]; then # clean
local git="$git%{%B%F{2}%}✓%{%f%b%}";
else
if [ 0 != $counts[1] ]; then # indexed
local git="$git%{%F{2}%}*$counts[1]%{%f%}"
fi
if [ 0 != $counts[2] ]; then # modified
local git="$git%{%F{1}%}+$counts[2]%{%f%}";
fi
if [ 0 != $counts[3] ]; then # deleted
local git="$git%{%F{1}%}-$counts[3]%{%f%}";
fi
if [ 0 != $counts[4] ]; then # unmerged
local git="$git%{%B%F{1}%}×$counts[4]%{%f%b%}";
fi
if [ 0 != $counts[5] ]; then # untracked
local git="$git%{%F{1}%}…%{%f%}";
fi
fi
fi
fi
fi
# Construct the prompt string
local line="$time_stamp $directory $git"
# Print the first line of the prompt
if [[ $exit_code -eq 0 ]]; then
print -P "$line"
else
# The last command failed, display its error code at the right
local result="%{%B%F{1}%}$exit_code%{%f%b%}"
local length=`visible_length "$line$result"`
print -P "$line${(l:COLUMNS - $length - 1:: :)}$result"
fi
}
visible_length() {
echo $(( ${#${(S%%)1//(\%(KF1]|)\{*\}|\%[Bbkf])}} ))
}
compile_git_prompt() {
# Compile a simple C executable which parses the output of `git status
# --procelain` to greatly decrease the time taken to render the prompt
if [ ! -d ~/.cache/zsh ]; then mkdir -p ~/.cache/zsh; fi
if [ ! -f ~/.cache/zsh/git-prompt ]; then
cc -x c -std=gnu99 -O3 -DNDEBUG -o ~/.cache/zsh/git-prompt - << EOF
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *file = popen("git status --porcelain", "r");
if (NULL == file) { return 0; }
char status[2048];
int indexed = 0, modified = 0, deleted = 0, untracked = 0, unmerged = 0;
while (NULL != fgets(status, sizeof(status) - 1, file)) {
char X = status[0];
char Y = status[1];
if (X == '?' && Y == '?') {
++untracked;
} else if ((X == 'A' && (Y == 'A' || Y == 'U')) ||
(X == 'D' && (Y == 'D' || Y == 'U')) ||
(X == 'U' && (Y == 'A' || Y == 'D' || Y == 'D' || Y == 'U'))) {
++unmerged;
} else {
switch (X) {
case ' ':
switch (Y) {
case 'M': ++modified; break;
case 'D': ++deleted; break;
} break;
case 'D': ++indexed;
switch (Y) {
case ' ': break;
case 'M': ++modified; break;
} break;
case 'M': case 'A': case 'R': case 'C': ++indexed;
switch (Y) {
case ' ': break;
case 'M': ++modified; break;
case 'D': ++deleted; break;
} break;
}
}
}
pclose(file);
if (indexed || modified || deleted || unmerged || untracked) {
printf("%d %d %d %d %d", indexed, modified, deleted, unmerged, untracked);
}
return 0;
}
EOF
fi
}
prompt_fresh_setup "$@"
# vim:ft=zsh