# Copyright (c) 2022 Igor Bogomazov # 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