Last active
June 5, 2021 16:03
-
-
Save iamtew/7006481 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/env bash | |
# Skip all of this if we don't have a TTY | |
tty -s || return 0 | |
# Colors + \[...\] wrapping to ensure there's no odd wrapping on command line | |
C_OFF="\[$(tput sgr0)\]" | |
C_BOLD="\[$(tput bold)\]" | |
C_BLACK="\[$(tput setaf 0)\]" | |
C_RED="\[$(tput setaf 1)\]" | |
C_GREEN="\[$(tput setaf 2)\]" | |
C_YELLOW="\[$(tput setaf 3)\]" | |
C_BLUE="\[$(tput setaf 4)\]" | |
C_MAGENTA="\[$(tput setaf 5)\]" | |
C_CYAN="\[$(tput setaf 6)\]" | |
C_WHITE="\[$(tput setaf 7)\]" | |
C_MAIN="$C_CYAN" | |
C_ROOT="$C_WHITE" | |
C_FAIL="$C_RED" | |
p_prefix="[" | |
p_suffix="]" | |
# p_prefix="┇" | |
# p_suffix="┆" | |
# p_prefix="「" | |
# p_suffix="」" | |
# Various variables for easier referencing | |
TIME24H="\t" | |
TIME12H="\T" | |
TIME12A="\@" | |
PATHSHORT="\w" | |
PATHFULL="\W" | |
HOSTNAMESHORT="\h" | |
HOSTNAMEFULL="\H" | |
NEWLINE="\n" | |
JOBS="\j" | |
# Command stack, use this to store last executed command | |
cmd_stack=() | |
trap 'cmd_stack=("${cmd_stack[@]}" "$BASH_COMMAND")' DEBUG | |
# Git information | |
__git_prompt() { | |
local git_prompt | |
local status | |
local branch | |
local ref | |
local dirty | |
local tracking | |
status=$(git status 2> /dev/null) | |
# Check dirty status | |
[[ -z $(git status --porcelain 2> /dev/null) ]] \ | |
&& dirty="${c_green}✓${c_off}" \ | |
|| dirty="${c_red}✗${c_off}" | |
# Get our branch or ref, depending if we're in detached HEAD or not. | |
ref=$(git symbolic-ref HEAD 2>/dev/null) \ | |
&& { ref=${ref#refs/heads/} ; branch="$ref" ; } \ | |
|| ref=$(git reflog HEAD | awk 'NR==1 && /checkout:/ { print $NF }') | |
# Check if we're ahead or behind upstream | |
if [[ -n "$branch" ]] ; then | |
local upstream_ref | |
local ahead | |
local behind | |
upstream_ref=$(git for-each-ref --format='%(refname:short) %(upstream:short)' refs/heads | awk -v branch="$branch" '"/^$branch/" { print $NF }') | |
if [[ -n "$upstream_ref" ]] ; then | |
ahead=$(git rev-list --count --left-right "$upstream_ref"...HEAD | cut -f1) | |
behind=$(git rev-list --count --left-right "$upstream_ref"...HEAD | cut -f2) | |
[[ $ahead -gt 0 ]] && tracking+="${C_CYAN}<${ahead}${C_OFF}:" | |
[[ $behind -gt 0 ]] && tracking+="${C_MAGENTA}<${behind}${C_OFF}:" | |
fi | |
fi | |
# Put together our prompt string | |
git_prompt+="[" | |
git_prompt+="${c_green}${ref}${c_off}:" | |
git_prompt+="${tracking}" | |
git_prompt+="${dirty}" | |
git_prompt+="]" | |
echo "$git_prompt" | |
} | |
prompt.git.dirty() { | |
local status | |
status=$(git status --porcelain 2> /dev/null) || return 1 | |
[[ -z $status ]] \ | |
&& echo "${C_GREEN}✓${C_OFF}" \ | |
|| echo "${C_RED}✗${C_OFF}" | |
} | |
prompt.git.updown() { | |
local branch | |
local tracking | |
local upstream_ref | |
local updown | |
local git_ahead | |
local git_behind | |
branch="$(prompt.git.branch)" | |
upstream_ref=$(git for-each-ref --format='%(refname:short)|%(upstream:short)' refs/heads \ | |
| grep "^$branch|" \ | |
| cut -d'|' -f2) | |
if [[ "$upstream_ref" ]]; then | |
updown=( $(git rev-list --count --left-right "$upstream_ref"...HEAD) ) | |
[[ ${updown[0]} -gt 0 ]] && tracking+="${C_CYAN}-${updown[0]}${C_OFF}:" # Behind | |
[[ ${updown[1]} -gt 0 ]] && tracking+="${C_MAGENTA}+${updown[1]}${C_OFF}:" # Ahead | |
# git_ahead=$(git rev-list --count --left-right "$upstream_ref"...HEAD | cut -f1) | |
# git_behind=$(git rev-list --count --left-right "$upstream_ref"...HEAD | cut -f2) | |
fi | |
echo "$tracking" | |
} | |
prompt.git.branch() { | |
local branch | |
branch="$(git symbolic-ref HEAD 2> /dev/null)" | |
branch="${branch#refs/heads/}" | |
# If we're in detached HEAD the above doesn't work, so use reflog instead | |
[[ -z $branch ]] && branch="$(git reflog HEAD | grep 'checkout:' | head -n1 | grep -oE '[^ ]+$')" | |
echo "$branch" | |
} | |
# Main prompt function | |
prompt() { | |
local cmd_exit="$?" # Exit code of previous command | |
local tformat="%T" | |
# If last command was this function, reset cmd_exit | |
[[ "${cmd_stack[@]}" == "prompt" ]] && cmd_exit=0 | |
# Reset stack | |
cmd_stack=() | |
# # Update the terminal title | |
if [[ "$TERM" =~ xterm* ]] ; then | |
echo -en "\033]0;${USER}@$(hostname -s):${PWD}\007" | |
fi | |
# Begin building up our prompt | |
# Change the color if we're root :^D | |
[[ $UID -eq 0 ]] && C_MAIN="$C_ROOT" | |
# Show previous command exit code if non-zero | |
PS1="${C_MAIN}${p_prefix}" | |
if [[ $cmd_exit -eq 0 ]] ; then | |
PS1+="$(date +$tformat)" | |
else | |
# Add some padding to look nice | |
case "${#cmd_exit}" in | |
1) PS1+="${C_FAIL}EXIT ${cmd_exit} " ;; | |
2) PS1+="${C_FAIL}EXIT ${cmd_exit} " ;; | |
3) PS1+="${C_FAIL}EXIT ${cmd_exit}" ;; | |
esac | |
# PS1+="${C_RED}EXIT ${cmd_exit}" | |
fi | |
PS1+="${C_YELLOW}:\w${C_MAIN}${p_suffix}${C_OFF}" | |
# Add Git information | |
if [[ -d .git ]] || [[ $(git status 2> /dev/null) ]]; then | |
PS1+="\n${C_GREEN}${p_prefix}" | |
PS1+="$(prompt.git.branch):$(prompt.git.updown)$(prompt.git.dirty)" | |
PS1+="${C_GREEN}${p_suffix}${C_OFF}" | |
fi | |
[[ -n $PL ]] \ | |
&& PS1+="$(tput setab 4)$(tput setaf 7)$(tput bold) $PL $(tput sgr0)" | |
# $ or # at the end of the prompt | |
PS1+='\$ ' | |
# Export variables to the environment | |
export PS1 | |
# Append last command to our history file | |
history -a | |
} | |
export PROMPT_DIRTRIM=2 | |
export PROMPT_COMMAND="prompt" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment