# Copyright (c) 2022 Igor Bogomazov <
[email protected]>
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# Supported shells:
# 1. bash
# 2. mksh / lksh
# 3. zsh
# 4. yash
# 5. dash
# 6. ksh93
# 7. busybox sh
# Some notes for future editions:
# 1. echo works differently in Bash and mksh, avoided here in favor of printf
# 2. this file is sourced from the main shell RC file, any combination of
# shell options is possible
# 3. ksh93 when sourcing a file reads it whole up, therefore no aliases
# defined in the same file get replaced
# 4. assuming terminal supports \b (backspace) character
# 5. PS1 expansion is not mandated by POSIX, more than that only parameter
# expansion is mentioned in the standard; this implementation relies on
# command substitution
# display GIT-repo and branch names
shrc_git_ps1() {
set -- "$(basename -- "$(
LC_ALL=C git rev-parse --show-toplevel 2>>/dev/null
)" )"
[ -z "$1" ] &&
return
set -- "$1" "$(
LC_ALL=C git branch 2>>/dev/null |
sed -nr 's@^\*[[:space:]]*(.*)$@\1@p; t lbl; b; :lbl q'
)"
printf ' [%s:%s]' "$1" "$2"
}
# display SVN root URL basename
shrc_svn_ps1() {
set -- "$( basename -- "$(
LC_ALL=C svn info 2>>/dev/null |
sed -nr '/Root:/ s@^.*[[:space:]]([^[:space:]]+)$@\1@p; t lbl; b; :lbl q'
)" )"
[ -z "$1" ] &&
return
printf ' [SVN:%s]' "$1"
}
# set red color if non-zero exit code
shrc_dollar_color() {
[ $shrc_exit_code -eq 0 ] &&
return
printf '\033[01;31m'
}
# display exit code with dollar sign if the last command failed
shrc_dollar_ps1() {
[ "$shrc_exit_code" -ne 0 ] &&
printf '(%s)' "$shrc_exit_code"
printf '%s' '$'
}
shrc_erase_text() {
while [ ${#1} -gt 0 ] ; do
printf '\b'
set -- "${1%?}"
done
}
# variable to keep the exit code of the last command
shrc_exit_code=
# newline character
# bash-5.0 (fixed in 5.1): \n behaved wrong with lines wider than a screen
shrc_newline="$(printf '\n.')"
shrc_newline="${shrc_newline%.}"
# assume it is Bash, that means \[ and \] are markers for zero width sequences
PS1=
# remember exit code of the previous command
PS1="$PS1"'\[$((shrc_exit_code=$?))$(shrc_erase_text "$shrc_exit_code")\]'
# print out date before each prompt
PS1="$PS1"'$(date)'"$shrc_newline"
# display username and hostname in green
PS1="$PS1"'\[$(printf "\033[01;32m")\]'
PS1="$PS1"'$(whoami)@$(hostname)'
PS1="$PS1"'\[$(printf "\033[00m")\]'
PS1="$PS1"':'
# working directory in blue
PS1="$PS1"'\[$(printf "\033[01;34m")\]'
PS1="$PS1"'$PWD'
PS1="$PS1"'\[$(printf "\033[00m")\]'
# display git info
PS1="$PS1"'\[$(printf "\033[01m")\]'
PS1="$PS1"'$(shrc_git_ps1)'
PS1="$PS1"'\[$(printf "\033[00m")\]'
# display SVN info
PS1="$PS1"'\[$(printf "\033[01m")\]'
PS1="$PS1"'$(shrc_svn_ps1)'
PS1="$PS1"'\[$(printf "\033[00m")\]'
# display colorful dollar sign
PS1="$PS1"'\[$(shrc_dollar_color)\]'
PS1="$PS1"'$(shrc_dollar_ps1)'
# reset any text attributes and append whitespace
PS1="$PS1"'\[$(printf "\033[00m")\] '
if printf '%s\n' "${KSH_VERSION-}" | grep -qiw ksh ; then
# change markers for non-printing sequences if in MirBSD ksh
PS1="$(printf '%s\n' "$PS1" | sed -r 's/\\[]\[]/'$'\001''/g')"
PS1="$(printf '\001\r%s' "$PS1")"
elif [ -n "${ZSH_VERSION-}" ] ; then
# change markers for non-printing sequences if in zsh
PS1="$(printf '%s\n' "$PS1" | sed -r 's/\\\[/%{/g ; s/\\\]/%}/g')"
# and enable PS1 expansion as in bash/ksh
setopt PROMPT_SUBST
elif [ -n "${YASH_VERSION:-}" ] ; then
# yash uses bash-style markers
true
elif [ -z "${BASH_VERSION-}" ] ; then
# for other shells just remove the markers
PS1="$(printf '%s\n' "$PS1" | sed -r 's/\\[]\[]//g')"
fi