211 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
| prompt_fresh_help() {
 | ||
|   echo "\
 | ||
| options:
 | ||
|         -a      enable almostontop like behaviour"
 | ||
| }
 | ||
| 
 | ||
| prompt_fresh_setup() {
 | ||
|   fresh_compile_git_prompt
 | ||
| 
 | ||
|   # Parse options
 | ||
|   local almostontop=0
 | ||
|   while getopts 'a' opt; do
 | ||
|     case $opt in
 | ||
|       a) local almostontop=1 ;;
 | ||
|       *) prompt -h fresh; return 1 ;;
 | ||
|     esac
 | ||
|   done
 | ||
| 
 | ||
|   autoload -U add-zsh-hook
 | ||
| 
 | ||
|   # Hook to print the first line of the "two line" prompt, this line is not
 | ||
|   # actually part of the prompt so does not get redrawn, this is preferable
 | ||
|   # since sometimes lines before the prompt can disappear.
 | ||
|   add-zsh-hook precmd fresh_line_one
 | ||
| 
 | ||
|   if [ $almostontop -eq 1 ]; then
 | ||
|     # Hook to clear the screen then prints the prompt with previous command at
 | ||
|     # the top of the screen.
 | ||
|     add-zsh-hook preexec fresh_almostontop
 | ||
|   else
 | ||
|     add-zsh-hook -d preexec fresh_almostontop
 | ||
|   fi
 | ||
| 
 | ||
|   if [ "$USER" = "root" ]; then
 | ||
|     local user="%{%F{1}%}%n%{%f%}"
 | ||
|   else
 | ||
|     local user="%{%F{35}%}%n%{%f%}"
 | ||
|   fi
 | ||
| 
 | ||
|   local userhost=$USER
 | ||
|   if [ "$SSH_CONNECTION" != "" ]; then
 | ||
|     local user="$user@%{%F{244}%}%M%{%f%}"
 | ||
|     local userhost="$userhost@`hostname`"
 | ||
|   fi
 | ||
| 
 | ||
|   PS1="«$user» "
 | ||
|   PS2="«${(l:${#userhost}:: :)}» "
 | ||
| 
 | ||
|   prompt_opts=(percent sp subst)
 | ||
| }
 | ||
| 
 | ||
| prompt_cleanup() {
 | ||
|   if [ -f ~/.cache/zsh/git-prompt ]; then rm ~/.cache/zsh/git-prompt; fi
 | ||
| }
 | ||
| 
 | ||
| fresh_line_one() {
 | ||
|   # 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%}"
 | ||
|   [[ -n $SANDBOX_HOME ]] && \
 | ||
|     local directory="%{%F{3}%}$SANDBOX_NAME${PWD#$SANDBOX_HOME}%{%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
 | ||
| 
 | ||
|   # If the last command failed, display its error code at the right
 | ||
|   if [[ $exit_code -ne 0 ]]; then
 | ||
|     local result=" %{%B%F{1}%}$exit_code%{%f%b%}"
 | ||
|   fi
 | ||
| 
 | ||
|   # If a virtualenv is enabled, display it's basename
 | ||
|   if [[ ! -z "$VIRTUAL_ENV" ]]; then
 | ||
|     local py=" %{%F{4}%}py%{%f%}%{%F{3}%}$(basename $VIRTUAL_ENV)%{%f%}"
 | ||
|   fi
 | ||
| 
 | ||
|   # If docker-machine env is active, display the machines name
 | ||
|   if [[ ! -z "$DOCKER_MACHINE_NAME" ]]; then
 | ||
|     local docker=" %{%F{6}%}$DOCKER_MACHINE_NAME%{%f%}"
 | ||
|   fi
 | ||
| 
 | ||
|   # Print the first line of the prompt
 | ||
|   print -P "$time_stamp $directory$git$py$docker$result"
 | ||
| }
 | ||
| 
 | ||
| fresh_almostontop() {
 | ||
|   clear
 | ||
|   fresh_line_one
 | ||
|   print -P "$PROMPT"'$1'
 | ||
| }
 | ||
| 
 | ||
| fresh_compile_git_prompt() {
 | ||
|   # Compile a simple C program which parses the output of `git status
 | ||
|   # --procelain` to greatly decrease the time taken to draw the prompt
 | ||
|   local cache=~/.cache/zsh; [ ! -d $cache ] && mkdir -p $cache
 | ||
|   if [ ! -f $cache/git-prompt ]; then
 | ||
|     cc -x c -std=gnu99 -O3 -DNDEBUG -o $cache/git-prompt - 2> /dev/null << 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
 | ||
|     if [ $? -ne 0 ]; then
 | ||
|       echo "git prompt disabled, are the system development headers installed?"
 | ||
|     fi
 | ||
|   fi
 | ||
| }
 | ||
| 
 | ||
| prompt_fresh_setup "$@"
 | ||
| 
 | ||
| # vim:ft=zsh
 |