Created
November 3, 2023 14:32
-
-
Save jonjitsu/23c7c57f18832c3f80a888952b2f67ed to your computer and use it in GitHub Desktop.
Bash prompt
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
PROMPT_BOLD="$COLOR_BOLD" | |
USER_COLOR="$COLOR_BOLD_BLUE" | |
PREPOSITION_COLOR="$COLOR_BOLD_WHITE" | |
DEVICE_COLOR="$COLOR_BOLD_CYAN" | |
DIR_COLOR="$COLOR_BOLD_GREEN" | |
COLOR_YELLOW="$COLOR_BOLD_YELLOW" | |
GIT_PROGRESS_COLOR="$COLOR_BOLD_RED" | |
SYMBOL_COLOR="$PROMPT_BOLD" # BOLD | |
# Define the default prompt terminator character '$' | |
if [[ "$UID" == 0 ]]; then | |
jonjitsu_bash_prompt_symbol="#" | |
else | |
jonjitsu_bash_prompt_symbol="\$" | |
fi | |
# Apply any color overrides that have been set in the environment | |
if [[ -n "$PROMPT_USER_COLOR" ]]; then USER_COLOR="$PROMPT_USER_COLOR"; fi | |
if [[ -n "$PROMPT_PREPOSITION_COLOR" ]]; then PREPOSITION_COLOR="$PROMPT_PREPOSITION_COLOR"; fi | |
if [[ -n "$PROMPT_DEVICE_COLOR" ]]; then DEVICE_COLOR="$PROMPT_DEVICE_COLOR"; fi | |
if [[ -n "$PROMPT_DIR_COLOR" ]]; then DIR_COLOR="$PROMPT_DIR_COLOR"; fi | |
if [[ -n "$PROMPT_GIT_STATUS_COLOR" ]]; then COLOR_YELLOW="$PROMPT_GIT_STATUS_COLOR"; fi | |
if [[ -n "$PROMPT_GIT_PROGRESS_COLOR" ]]; then GIT_PROGRESS_COLOR="$PROMPT_GIT_PROGRESS_COLOR"; fi | |
if [[ -n "$PROMPT_SYMBOL" ]]; then jonjitsu_bash_prompt_symbol="$PROMPT_SYMBOL"; fi | |
if [[ -n "$PROMPT_SYMBOL_COLOR" ]]; then SYMBOL_COLOR="$PROMPT_SYMBOL_COLOR"; fi | |
# Set up symbols | |
jonjitsu_bash_prompt_synced_symbol="" | |
jonjitsu_bash_prompt_dirty_synced_symbol="*" | |
jonjitsu_bash_prompt_unpushed_symbol="△" | |
jonjitsu_bash_prompt_dirty_unpushed_symbol="▲" | |
jonjitsu_bash_prompt_unpulled_symbol="▽" | |
jonjitsu_bash_prompt_dirty_unpulled_symbol="▼" | |
jonjitsu_bash_prompt_unpushed_unpulled_symbol="⬡" | |
jonjitsu_bash_prompt_dirty_unpushed_unpulled_symbol="⬢" | |
# Apply symbol overrides that have been set in the environment | |
# DEV: Working unicode symbols can be determined via the following gist | |
# **WARNING: The following gist has 64k lines and may freeze your browser** | |
# https://gist.github.com/twolfson/9cc7968eb6ee8b9ad877 | |
if [[ -n "$PROMPT_SYNCED_SYMBOL" ]]; then jonjitsu_bash_prompt_synced_symbol="$PROMPT_SYNCED_SYMBOL"; fi | |
if [[ -n "$PROMPT_DIRTY_SYNCED_SYMBOL" ]]; then jonjitsu_bash_prompt_dirty_synced_symbol="$PROMPT_DIRTY_SYNCED_SYMBOL"; fi | |
if [[ -n "$PROMPT_UNPUSHED_SYMBOL" ]]; then jonjitsu_bash_prompt_unpushed_symbol="$PROMPT_UNPUSHED_SYMBOL"; fi | |
if [[ -n "$PROMPT_DIRTY_UNPUSHED_SYMBOL" ]]; then jonjitsu_bash_prompt_dirty_unpushed_symbol="$PROMPT_DIRTY_UNPUSHED_SYMBOL"; fi | |
if [[ -n "$PROMPT_UNPULLED_SYMBOL" ]]; then jonjitsu_bash_prompt_unpulled_symbol="$PROMPT_UNPULLED_SYMBOL"; fi | |
if [[ -n "$PROMPT_DIRTY_UNPULLED_SYMBOL" ]]; then jonjitsu_bash_prompt_dirty_unpulled_symbol="$PROMPT_DIRTY_UNPULLED_SYMBOL"; fi | |
if [[ -n "$PROMPT_UNPUSHED_UNPULLED_SYMBOL" ]]; then jonjitsu_bash_prompt_unpushed_unpulled_symbol="$PROMPT_UNPUSHED_UNPULLED_SYMBOL"; fi | |
if [[ -n "$PROMPT_DIRTY_UNPUSHED_UNPULLED_SYMBOL" ]]; then jonjitsu_bash_prompt_dirty_unpushed_unpulled_symbol="$PROMPT_DIRTY_UNPUSHED_UNPULLED_SYMBOL"; fi | |
function jonjitsu_bash_prompt_get_git_branch() { | |
# On branches, this will return the branch name | |
# On non-branches, (no branch) | |
ref="$(git symbolic-ref HEAD 2> /dev/null | sed -e 's/refs\/heads\///')" | |
if [[ "$ref" != "" ]]; then | |
echo "$ref" | |
else | |
echo "(no branch)" | |
fi | |
} | |
function jonjitsu_bash_prompt_get_git_progress() { | |
# Detect in-progress actions (e.g. merge, rebase) | |
# https://github.com/git/git/blob/v1.9-rc2/wt-status.c#L1199-L1241 | |
git_dir="$(git rev-parse --git-dir)" | |
# git merge | |
if [[ -f "$git_dir/MERGE_HEAD" ]]; then | |
echo " [merge]" | |
elif [[ -d "$git_dir/rebase-apply" ]]; then | |
# git am | |
if [[ -f "$git_dir/rebase-apply/applying" ]]; then | |
echo " [am]" | |
# git rebase | |
else | |
echo " [rebase]" | |
fi | |
elif [[ -d "$git_dir/rebase-merge" ]]; then | |
# git rebase --interactive/--merge | |
echo " [rebase]" | |
elif [[ -f "$git_dir/CHERRY_PICK_HEAD" ]]; then | |
# git cherry-pick | |
echo " [cherry-pick]" | |
fi | |
if [[ -f "$git_dir/BISECT_LOG" ]]; then | |
# git bisect | |
echo " [bisect]" | |
fi | |
if [[ -f "$git_dir/REVERT_HEAD" ]]; then | |
# git revert --no-commit | |
echo " [revert]" | |
fi | |
} | |
jonjitsu_bash_prompt_is_branch1_behind_branch2 () { | |
# $ git log origin/master..master -1 | |
# commit 4a633f715caf26f6e9495198f89bba20f3402a32 | |
# Author: Todd Wolfson <todd@twolfson.com> | |
# Date: Sun Jul 7 22:12:17 2013 -0700 | |
# | |
# Unsynced commit | |
# Find the first log (if any) that is in branch1 but not branch2 | |
first_log="$(git log $1..$2 -1 2> /dev/null)" | |
# Exit with 0 if there is a first log, 1 if there is not | |
[[ -n "$first_log" ]] | |
} | |
jonjitsu_bash_prompt_branch_exists () { | |
# List remote branches | # Find our branch and exit with 0 or 1 if found/not found | |
git branch --remote 2> /dev/null | grep --quiet "$1" | |
} | |
jonjitsu_bash_prompt_parse_git_ahead () { | |
# Grab the local and remote branch | |
branch="$(jonjitsu_bash_prompt_get_git_branch)" | |
remote_branch="origin/$branch" | |
# $ git log origin/master..master | |
# commit 4a633f715caf26f6e9495198f89bba20f3402a32 | |
# Author: Todd Wolfson <todd@twolfson.com> | |
# Date: Sun Jul 7 22:12:17 2013 -0700 | |
# | |
# Unsynced commit | |
# If the remote branch is behind the local branch | |
# or it has not been merged into origin (remote branch doesn't exist) | |
if (jonjitsu_bash_prompt_is_branch1_behind_branch2 "$remote_branch" "$branch" || | |
! jonjitsu_bash_prompt_branch_exists "$remote_branch"); then | |
# echo our character | |
echo 1 | |
fi | |
} | |
prompt.parse_git_behind () { | |
# Grab the branch | |
branch="$(jonjitsu_bash_prompt_get_git_branch)" | |
remote_branch="origin/$branch" | |
# $ git log master..origin/master | |
# commit 4a633f715caf26f6e9495198f89bba20f3402a32 | |
# Author: Todd Wolfson <todd@twolfson.com> | |
# Date: Sun Jul 7 22:12:17 2013 -0700 | |
# | |
# Unsynced commit | |
# If the local branch is behind the remote branch | |
if jonjitsu_bash_prompt_is_branch1_behind_branch2 "$branch" "$remote_branch"; then | |
# echo our character | |
echo 1 | |
fi | |
} | |
function jonjitsu_bash_prompt_parse_git_dirty() { | |
# If the git status has *any* changes (e.g. dirty), echo our character | |
if [[ -n "$(git status --porcelain 2> /dev/null)" ]]; then | |
echo 1 | |
fi | |
} | |
function jonjitsu_bash_prompt_is_on_git() { | |
git rev-parse 2> /dev/null | |
} | |
function jonjitsu_bash_prompt_get_git_status() { | |
# Grab the git dirty and git behind | |
dirty_branch="$(jonjitsu_bash_prompt_parse_git_dirty)" | |
branch_ahead="$(jonjitsu_bash_prompt_parse_git_ahead)" | |
branch_behind="$(prompt.parse_git_behind)" | |
# Iterate through all the cases and if it matches, then echo | |
if [[ "$dirty_branch" == 1 && "$branch_ahead" == 1 && "$branch_behind" == 1 ]]; then | |
echo "$jonjitsu_bash_prompt_dirty_unpushed_unpulled_symbol" | |
elif [[ "$branch_ahead" == 1 && "$branch_behind" == 1 ]]; then | |
echo "$jonjitsu_bash_prompt_unpushed_unpulled_symbol" | |
elif [[ "$dirty_branch" == 1 && "$branch_ahead" == 1 ]]; then | |
echo "$jonjitsu_bash_prompt_dirty_unpushed_symbol" | |
elif [[ "$branch_ahead" == 1 ]]; then | |
echo "$jonjitsu_bash_prompt_unpushed_symbol" | |
elif [[ "$dirty_branch" == 1 && "$branch_behind" == 1 ]]; then | |
echo "$jonjitsu_bash_prompt_dirty_unpulled_symbol" | |
elif [[ "$branch_behind" == 1 ]]; then | |
echo "$jonjitsu_bash_prompt_unpulled_symbol" | |
elif [[ "$dirty_branch" == 1 ]]; then | |
echo "$jonjitsu_bash_prompt_dirty_synced_symbol" | |
else # clean | |
echo "$jonjitsu_bash_prompt_synced_symbol" | |
fi | |
} | |
analyze_git() { | |
git status --porcelain 2> /dev/null \ | |
| awk ' | |
BEGIN { d=0; s=0; } | |
/^(\?| )/ { d++; next; } | |
{ s++; } | |
END { print d, s }' | |
} | |
prompt.get_git_info () { | |
# Grab the branch | |
branch="$(jonjitsu_bash_prompt_get_git_branch)" | |
local other="" | |
# If there are any branches | |
if [[ "$branch" != "" ]]; then | |
read dirty staged <<<$(analyze_git) | |
if [[ $dirty -eq 0 ]] && [[ $staged -eq 0 ]]; then | |
output="${DIR_COLOR}${branch}" | |
else | |
if [[ $staged -gt 0 ]]; then | |
output="${COLOR_YELLOW}${branch}" | |
if [[ $dirty -gt 0 ]]; then | |
other="${COLOR_RESET}|${GIT_PROGRESS_COLOR}${dirty}${COLOR_YELLOW}" | |
fi | |
other="${COLOR_RESET}|${COLOR_YELLOW}${staged}${other}" | |
else | |
output="${GIT_PROGRESS_COLOR}${branch}" | |
other="${COLOR_RESET}|${GIT_PROGRESS_COLOR}${dirty}" | |
fi | |
fi | |
# if [[ ${git_status} =~ "working tree clean" ]]; then | |
# state="${DIR_COLOR}" | |
# elif [[ ${git_status} =~ "Changes to be committed" ]]; then | |
# state="${COLOR_YELLOW}" | |
# else | |
# state="${GIT_PROGRESS_COLOR}" | |
# fi | |
# # Echo the branch | |
# output="${state}${branch}" | |
# Add on the git status | |
output="$output$(jonjitsu_bash_prompt_get_git_status)${other}" | |
# Echo our output | |
echo "$output" | |
fi | |
} | |
PROMPT_COMMAND_HOOKS=() | |
prompt.add_hook() { | |
PROMPT_COMMAND_HOOKS+=("$@") | |
} | |
prompt.run_hooks() { | |
for cmd in "${PROMPT_COMMAND_HOOKS[@]}"; do | |
# type -p "$cmd" && "$cmd" | |
$cmd | |
done | |
} | |
prompt.hooks() { | |
for cmd in "${PROMPT_COMMAND_HOOKS[@]}"; do | |
echo - "$cmd" | |
done | |
} | |
prompt.command() | |
{ | |
local PREV_RET_VAL=$? | |
local VE="" | |
local parts=() | |
local aws | |
if [[ -n $AWS_DEFAULT_PROFILE ]] | |
then echo "prompt: AWS_DEFAULT_PROFILE is deprecated. Switching to AWS_PROFILE" >&2 | |
export AWS_PROFILE="$AWS_DEFAULT_PROFILE" | |
unset AWS_DEFAULT_PROFILE | |
fi | |
if [[ -n $AWS_PROFILE ]]; then | |
aws="\[$COLOR_BOLD_WHITE\]aws:\[$COLOR_BLUE\]${AWS_PROFILE}\[$COLOR_RESET\]" | |
elif [[ -n $AWS_ACCESS_KEY_ID ]] && [[ -n $AWS_SECRET_ACCESS_KEY ]]; then | |
aws="\[$COLOR_BOLD_WHITE\]aws:\[$COLOR_BLUE\]VARS\[$COLOR_RESET\]" | |
fi | |
if [[ -n $aws ]]; then | |
if [[ -n $AWS_DEFAULT_REGION ]]; then | |
aws="$aws:\[$COLOR_BLUE\]${AWS_DEFAULT_REGION}\[$COLOR_RESET\]" | |
fi | |
parts+=($aws) | |
fi | |
if [[ -f $HOME/.config/gcloud/active_config ]] | |
then parts+=("\[$COLOR_BOLD_WHITE\]gcp:\[$COLOR_BLUE\]$(cat "$HOME/.config/gcloud/active_config")\[$COLOR_RESET\]") | |
fi | |
if [[ -n $VIRTUAL_ENV ]]; then | |
local p=${VIRTUAL_ENV##*/} | |
parts+=("\[$COLOR_BOLD_WHITE\]py:\[$COLOR_BLUE\]${p}\[$COLOR_RESET\]") | |
# VE="$VE (\[$COLOR_YELLOW\]${p}\[$COLOR_RESET\])" | |
fi | |
if [[ -n $RUBYVENV ]]; then | |
parts+=("\[$COLOR_BOLD_WHITE\]rb:\[$COLOR_BLUE\]${RUBYVENV}\[$COLOR_RESET\]") | |
# VE="$VE(\[$COLOR_PURPLE\]${RUBYVENV}\[$COLOR_RESET\])" | |
fi | |
if [[ -n $NAVE ]]; then | |
parts+=("\[$COLOR_BOLD_WHITE\]js:\[$COLOR_BLUE\]${NAVE}\[$COLOR_RESET\]") | |
# VE="$VE(\[$COLOR_PURPLE\]${NAVE}\[$COLOR_RESET\])" | |
fi | |
local pulumi_login | |
if [[ -f $HOME/.pulumi/credentials.json ]] | |
then pulumi_login="$(jq -r .current ~/.pulumi/credentials.json)" | |
if [[ -n $pulumi_login ]] && [[ $pulumi_login != "null" ]] | |
then parts+=("\[$COLOR_BOLD_WHITE\]pu:\[$COLOR_BLUE\]${pulumi_login}\[$COLOR_RESET\]") | |
fi | |
fi | |
# local IFS='|' | |
VE="${parts[*]} " | |
local TS="\d \t" | |
# TS="$(TZ=UTC date '+%a %b %d %T %Z')" | |
# TS="$(TZ=UTC date --iso-8601=seconds)" | |
# TS="$(TZ=UTC date '+%Y-%m-%d %T %Z')" | |
TS="$(TZ=UTC date '+%Y-%m-%d %T') $(date +%:z)" | |
PS1="$TS \[$USER_COLOR\]\u\[$COLOR_RESET\]\ | |
\[$PREPOSITION_COLOR\]@\[$COLOR_RESET\]\ | |
\[$DEVICE_COLOR\]\h\[$COLOR_RESET\]\ | |
\[$PREPOSITION_COLOR\]\[$COLOR_RESET\] \ | |
\[$DIR_COLOR\]\w\[$COLOR_RESET\]\$(jonjitsu_bash_prompt_is_on_git && \ | |
echo -ne \" \[$PREPOSITION_COLOR\][\[$COLOR_RESET\]\" && \ | |
echo -ne \"\[$COLOR_YELLOW\]\$(prompt.get_git_info)\" && \ | |
echo -ne \"\[$GIT_PROGRESS_COLOR\]\$(jonjitsu_bash_prompt_get_git_progress)\" && \ | |
echo -ne \"\[$PREPOSITION_COLOR\]]\") $VE" | |
if test $PREV_RET_VAL -eq 0 | |
then | |
PS1="${PS1}\[$COLOR_RESET\]\n" | |
else | |
PS1="(\[$GIT_PROGRESS_COLOR\]${PREV_RET_VAL}\[$COLOR_RESET\]) ${PS1}\[$COLOR_RESET\]\n" | |
fi | |
prompt.run_hooks | |
} | |
PROMPT_COMMAND=prompt.command |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment