Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
gayterm/.bash_prompt
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
150 lines (132 sloc)
4.62 KB
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
# shellcheck shell=bash | |
# Customize bash prompt | |
# lolcat reference: http://apple.stackexchange.com/a/266112/216733 | |
# If dynamic can use literal control characters. Otherwise, | |
# must use PS1 escapes or else line wrap issue. | |
PROMPT_COMMAND="__prompt_command${PROMPT_COMMAND:+"; $PROMPT_COMMAND"}" | |
PS1_COLORIZE_COMMAND='__ps1_lolcat' | |
# shellcheck disable=SC2034 | |
PS1_DEBUG_COMMAND='__ps1_debug' | |
PS1_DEBUG='false' | |
__prompt_command() { | |
# Save last exit code | |
PS1_exit=$? | |
if [[ "$PS1_DEBUG" = 'true' ]]; then | |
if [[ "$PS1" = "$PS1_DEBUG_DISABLED" ]]; then | |
PS1=$PS1_DEBUG_ENABLED | |
fi | |
else | |
if [[ "$PS1" = "$PS1_DEBUG_ENABLED" ]]; then | |
PS1=$PS1_DEBUG_DISABLED | |
fi | |
fi | |
} | |
ps1_set_debug_mode() { | |
if [[ "$PS1_DEBUG" = 'true' ]]; then | |
PS1=$PS1_DEBUG_ENABLED | |
else | |
PS1=$PS1_DEBUG_DISABLED | |
fi | |
} | |
TERM_DEFAULT=$(tput sgr0) | |
TERM_RED=$(tput setaf 1) | |
TERM_GREEN=$(tput setaf 2) | |
TERM_BLUE=$(tput setaf 4) | |
ESC=$'\033' | |
SOH=$'\001' | |
STX=$'\002' | |
PS1_DEFAULT_LITERAL=$SOH$TERM_DEFAULT$STX | |
PS1_RED_LITERAL=$SOH$TERM_RED$STX | |
PS1_GREEN_LITERAL=$SOH$TERM_GREEN$STX | |
PS1_BLUE_LITERAL=$SOH$TERM_BLUE$STX | |
PS1_DEFAULT_ESCAPED='\['$TERM_DEFAULT'\]' | |
PS1_RED_ESCAPED='\['$TERM_RED'\]' | |
PS1_GREEN_ESCAPED='\['$TERM_GREEN'\]' | |
# Caveat: | |
# to have a literal '\' or '"' work in both $PS1_DEBUG_DISABLED and | |
# $PS1_DEBUG_ENABLED, '\' must be represented with '\\\\' and | |
# '"' must be represented with '\\"' or '\"' to have the proper amount of | |
# escaping in both modes. PS1 seems to have an initial interpret phase where | |
# it strips off one level of backslashes, then an echo phase where it strips | |
# off the second level so '\\\\' =interpret> '\\' =echo> '\' | |
# '\\"' =interpret> '\"' =echo> '"' | |
# The following is a bit trickier. Normally, echo would treat the double quote | |
# as starting a string. PS1 seems to treat it as a literal when echoing. As | |
# a result, '\\"' is preferred over '\"' as it is easier to understand what is | |
# happening. | |
# '\"' =interpret> 'literal(")' =echo> '"' | |
# In $PS1_DEBUG_ENABLED, the interpret phase is still run by PS1. The echo | |
# phase is emulated by wrapping $PS1 in double quotes: ...<<<"'PS1'"... | |
unset PS1 | |
PS1_COLORLESS=$(sed 's/[[:space:]]*$//' <<<"${PS1:-\h:\W \u\\$}") | |
PS1_SPACING=' ' | |
PS1='' | |
PS1_HISTORY_NUMBER='\!)' | |
PS1+='$(eval "$PS1_COLORIZE_COMMAND" <<<"'$PS1_HISTORY_NUMBER'")' | |
PS1+=$PS1_SPACING | |
# Rule is to use PS1_{COLOR}_ESCAPED if the escape sequence appears in PS1, but | |
# use PS1_{COLOR}_LITERAL if it doesn't e.g. it's inside a function. | |
PS1+='[' | |
PS1+='$(' | |
PS1+='if ((PS1_exit == 0)); then ' | |
PS1+="echo '$PS1_GREEN_ESCAPED'; " | |
PS1+='else ' | |
PS1+="echo '$PS1_RED_ESCAPED'; fi" | |
PS1+=')' | |
PS1+='$PS1_exit' | |
PS1+=$PS1_DEFAULT_ESCAPED | |
PS1+=']' | |
PS1+=$PS1_SPACING | |
PS1+='$(eval "$PS1_COLORIZE_COMMAND" <<<"'$PS1_COLORLESS'")' | |
PS1+=$PS1_SPACING | |
PS1_DEBUG_DISABLED=$PS1 | |
# wrap PS1 for debugging | |
# shellcheck disable=SC2016 | |
PS1_DEBUG_ENABLED='$(eval "$PS1_DEBUG_COMMAND" <<<"'$PS1'")' | |
__ps1_remove_newline() { | |
tr -d '\n' | |
} | |
__ps1_color_wrap_non_printing() { | |
local REGEX=$ESC'\[[[:digit:];]*m' | |
local REPLACE=$SOH'&'$STX | |
sed "s/$REGEX/$REPLACE/g" | |
} | |
__ps1_lolcat_ruby() { | |
rbenv exec lolcat -f -F 6 -p 25 | __ps1_color_wrap_non_printing | |
} | |
__ps1_lolcat_python() { | |
pyenv exec lolcat -f -F 6 -p 25 | __ps1_remove_newline \ | |
| __ps1_color_wrap_non_printing | |
} | |
__ps1_lolcat() { | |
lolcat-c -f -h 0.8 | __ps1_remove_newline | __ps1_color_wrap_non_printing | |
} | |
# long colored prompt text that go over a line have a line wrap issue. | |
# Problem occurs with literal and PS1 escaped control characters. Tried | |
# escaping each individual character with perl at | |
# "$SCRIPTS_DIR"'/ps1_colorize_debug.pl' but still doesn't work. | |
# can't colorize debug literal text with sed because it does not have the | |
# following: | |
# non-greedy quantifiers to do \^B\(.*?\)\^A if running a second sed to | |
# consume \^B and \^A again. | |
# lookahead to do \(.*?)\(?=\^A) which wouldn't require a second sed because | |
# \^A is is looked for but not consumed. | |
# can use perl regex if want to colorize debug literal text. | |
# sed also doesn't have non capturing groups so groups are offset. | |
__ps1_colorize_debug() { | |
local SOH_REGEX='(\^A)' | |
local COLOR_CODE_REGEX='((\^\[\(B)?\^\[\[[[:digit:];]*m)' | |
local STX_REGEX='(\^B)' | |
local REGEX=$SOH_REGEX$COLOR_CODE_REGEX$STX_REGEX | |
local SOH_REPLACE=$PS1_RED_LITERAL'\1'$PS1_DEFAULT_LITERAL | |
local COLOR_CODE_REPLACE=$PS1_BLUE_LITERAL'\2'$PS1_DEFAULT_LITERAL | |
local STX_REPLACE=$PS1_GREEN_LITERAL'\4'$PS1_DEFAULT_LITERAL | |
local REPLACE=$SOH_REPLACE$COLOR_CODE_REPLACE$STX_REPLACE | |
sed -E "s/$REGEX/$REPLACE/g" | |
} | |
__ps1_debug() { | |
cat -v | __ps1_colorize_debug | |
} | |
__ps1_debug_sed() { | |
sed -e 's/'$ESC'/[ESC]/g' -e 's/'$SOH'/[SOH]/g' -e 's/'$STX'/[STX]/g' | |
} |