# All of this is only known to work on OpenBSD's fork of pdksh
[[ $(uname -s) == OpenBSD ]] || return
# Frontend to controlling prompt
prompt() {
# If no arguments, print the prompt strings as they are
if ! (($#)) ; then
printf '%s\n' PS1="$PS1" PS2="$PS2" PS3="$PS3" PS4="$PS4"
return
fi
# What's done next depends on the first argument to the function
case $1 in
# Turn complex, colored PS1 and debugging PS4 prompts on
on)
# Basic prompt shape depends on whether we're in SSH or not
PS1=
if [[ -n $SSH_CLIENT ]] || [[ -n $SSH_CONNECTION ]] ; then
PS1=$PS1'\u@\h:'
fi
PS1=$PS1'\w'
# Add sub-commands; VCS, job, and return status checks
PS1=$PS1'$(prompt vcs)$(prompt job)'
# Add prefix and suffix
PS1='${PROMPT_PREFIX}'$PS1'${PROMPT_SUFFIX}'
# Add terminating "$" or "#" sign
PS1=$PS1'\$'
# Count available colors
typeset -i colors
colors=$( {
tput Co || tput colors
} 2>/dev/null )
# Prepare reset code
typeset reset
reset=$( {
tput me || tput sgr0
} 2>/dev/null )
# Decide prompt color formatting based on color availability
typeset format
case $colors in
# Check if we have non-bold bright green available
256)
format=$( {
: "${PROMPT_COLOR:=12}"
tput AF "$PROMPT_COLOR" ||
tput setaf "$PROMPT_COLOR" ||
tput AF "$PROMPT_COLOR" 0 0 ||
tput setaf "$PROMPT_COLOR" 0 0
} 2>/dev/null )
;;
# If we have only eight colors, use bold green
8)
format=$( {
: "${PROMPT_COLOR:=4}"
tput AF "$PROMPT_COLOR" ||
tput setaf "$PROMPT_COLOR"
tput md || tput bold
} 2>/dev/null )
;;
# For all other terminals, we assume non-color (!), and we just
# use bold
*)
format=$( {
tput md || tput bold
} 2>/dev/null )
;;
esac
# String it all together
PS1='\['"$format"'\]'"$PS1"'\['"$reset"'\] '
PS2='> '
PS3='? '
PS4='+<$?> $LINENO:'
;;
# Git prompt function
git)
# Bail if we're not in a work tree--or, implicitly, if we don't
# have git(1).
typeset iswt
iswt=$(git rev-parse --is-inside-work-tree 2>/dev/null)
[[ $iswt = true ]] || return
# Refresh index so e.g. git-diff-files(1) is accurate
git update-index --refresh >/dev/null
# Find a local branch, remote branch, or tag (annotated or not), or
# failing all of that just show the short commit ID, in that order
# of preference; if none of that works, bail out
typeset name
name=$( {
git symbolic-ref --quiet HEAD ||
git describe --tags --exact-match HEAD ||
git rev-parse --short HEAD
} 2>/dev/null) || return
name=${name##*/}
[[ -n $name ]] || return
# Check various files in .git to flag processes
typeset proc
[[ -d .git/rebase-merge || -d .git/rebase-apply ]] &&
proc=${proc:+$proc,}'REBASE'
[[ -f .git/MERGE_HEAD ]] &&
proc=${proc:+$proc,}'MERGE'
[[ -f .git/CHERRY_PICK_HEAD ]] &&
proc=${proc:+$proc,}'PICK'
[[ -f .git/REVERT_HEAD ]] &&
proc=${proc:+$proc,}'REVERT'
[[ -f .git/BISECT_LOG ]] &&
proc=${proc:+$proc,}'BISECT'
# Collect symbols representing repository state
typeset state
# Upstream HEAD has commits after local HEAD; we're "behind"
typeset -i behind
behind=$(git rev-list --count 'HEAD..@{u}' 2>/dev/null)
((behind)) && state=${state}'<'
# Local HEAD has commits after upstream HEAD; we're "ahead"
typeset -i ahead
ahead=$(git rev-list --count '@{u}..HEAD' 2>/dev/null)
((ahead)) && state=${state}'>'
# Tracked files are modified; double exclamation mark because
# that's how you get a literal one in pdksh PS1
git diff-files --no-ext-diff --quiet ||
state=${state}'!!'
# Changes are staged
git diff-index --cached --no-ext-diff --quiet HEAD 2>/dev/null ||
state=${state}'+'
# There are some untracked and unignored files
git ls-files --directory --error-unmatch --exclude-standard \
--no-empty-directory --others -- ':/*' >/dev/null 2>&1 &&
state=${state}'?'
# There are stashed changes
git rev-parse --quiet --verify refs/stash >/dev/null &&
state=${state}'^'
# Print the status in brackets; add a git: prefix only if there
# might be another VCS prompt (because PROMPT_VCS is set)
printf '(%s%s%s%s)' \
"${PROMPT_VCS:+git:}" "$name" "${proc:+:$proc}" "$state"
;;
# Revert to simple inexpensive prompts
off)
PS1='\$ '
PS2='> '
PS3='? '
PS4='+ '
;;
# VCS wrapper prompt function; print the first relevant prompt, if any
vcs)
typeset vcs
for vcs in "${PROMPT_VCS[@]:-git}" ; do
prompt "$vcs" && return
done
;;
# Show the count of background jobs in curly brackets, if not zero
job)
typeset -i jobc
jobc=$(jobs -p | sed -n '$=')
((jobc)) && printf '{%u}' "$jobc"
;;
# Print error
*)
printf 'prompt: Unknown command %s\n' "$1" >&2
return 2
;;
esac
}
# Start with full-fledged prompt
prompt on