Skip to content

Instantly share code, notes, and snippets.

@jart jart/.jartps1.sh
Last active Mar 12, 2018

Embed
What would you like to do?
PS1 with low latency git branch detection
#!/bin/bash
# jartps1.sh - Enhanced bash prompt
# Author: Justine Tunney <jart@google.com>
# Modified: 2014-06-20
#
# LIST OF BASH PROMPT ENHANCEMENTS
#
# - No latency issues when holding down enter key
# - Doesn't look unfamiliar compared to bash defaults
# - Show current git branch
# - Show background job count if \j > 0
# - Show process exit code if $? != 0
#
# TRY IT OUT
#
# JARTPS1_THEME=dark source .jartps1.sh
#
# CUSTOMIZING
#
# Copy/paste the `PS1="..."` line from this file and add it to your bashrc
# after the line where you source this file and refer to the `man bash`
# section titled "PROMPTING".
#
# If you're using a black background terminal then you might want to
# customize the color and make things look more fabulous. You just have to
# figure out the ANSI escape codes for the colors you want. Don't remove the
# 0's because they're used to reset the current formatting. Also don't remove
# the \[...\] escapes or else bash will print artifacts when you do things
# like reverse search. A library called Fabulous will help you generate the
# escape codes:
#
# $ sudo apt-get install python-pip
# $ sudo pip install fabulous
# $ python
# >>> from fabulous import color
# >>> color.red('hello')
# u'\x1b[31mhello\x1b[39m'
# >>> color.fg256('#ff6699', 'hello')
# u'\x1b[38;5;204mhello\x1b[39m'
# >>> color.bold(color.flip(color.fg256('indianred', 'hello')))
# u'\x1b[1;7;38;5;167mhello\x1b[39;27;22m'
#
# See also: https://github.com/jart/fabulous/blob/master/fabulous/color.py
#
# NOTES
#
# This script will leave a tiny temp file behind for each terminal you
# open. This isn't a problem because `/etc/cron.daily/tmpreaper` will delete
# them after seven days or so.
#
# CHANGELOG
#
# 2014-06-20 Justine Tunney <jart@google.com>
#
# * Conform to go/bashstyle
#
# 2013-12-10 Justine Tunney <jart@google.com>
#
# * Fixed a bug which caused bash to display a warning each time the prompt
# is displayed if a certain /tmp file got deleted by a weekly cleanup
# cron job.
#
# * Fixed ps1_error() and ps1_jobs() now that I understand bash arithmetic
# expressions better.
#
case ${JARTPS1_THEME:-default} in
default)
PS1="\[\e[1;31m\]\$(ps1_error)\[\e[34m\]\$(ps1_jobs \j)\[\e[32m\]\$(ps1_git)\[\e[0m\]\u@\h\[\e[m\]:\$(ps1_dir)\$ "
PS2='> '
PS4='+ '
;;
dark)
PS1="\[\e[1;31m\]\$(ps1_error)\[\e[34m\]\$(ps1_jobs \j)\[\e[32m\]\$(ps1_git)\[\e[0;95m\]\u@\h\[\e[m\]:\[\e[0;96m\]\$(ps1_dir)\[\e[0m\]\$ "
PS2='> '
PS4='+ '
;;
*)
printf "Invalid \$JARTPS1_THEME: %s\n" "${JARTPS1_THEME}" >&2
;;
esac
ps1_error() {
local -i err=$?
if (( err != 0 )); then
printf "\$?=%d " ${err}
fi
}
ps1_jobs() {
local -i count=$1
if (( count > 0 )); then
printf "jobs=%d " ${count}
fi
}
ps1_git() {
if jartps1_gitbranch_find; then
printf "%s " "${jartps1_gitbranch}"
fi
}
ps1_dir() {
local path="${PWD}"
case "${path}" in
/home/${USER})
path="~"
;;
/home/${USER}/*)
path="~/${path#/home/*/}"
;;
esac
printf "%s" "${path}"
}
# Caches last directory for which `jartps1_gitdir_find` failed.
export JARTPS1_GITDIR_TMP="$(mktemp --suffix=-jartps1-gitdir)"
################################################################################
# Swiftly determine name of current Git branch.
#
# Arguments:
# None
# Returns:
# 0 on success, storing result to ${jartps1_gitbranch}.
# 1 if ${PWD} isn't inside a Git repo.
# Globals:
# jartps1_gitbranch - Used to store result.
################################################################################
jartps1_gitbranch_find() {
if jartps1_gitdir_find; then
local head
if read head <"${jartps1_gitdir}/.git/HEAD" &>/dev/null; then
jartps1_gitbranch="${head##*/}"
if [[ "${jartps1_gitbranch}" != "" ]]; then
return 0
fi
fi
fi
return 1
}
################################################################################
# Swiftly locate root of current Git repository.
#
# This is the fastest possible solution. Rather than the naïve approach of
# executing the git command (which could take hundreds of milliseconds), this
# routine launches no processes and only requires a few stat() system calls. In
# some cases it can avoid lookup or cache the result.
#
# Arguments:
# dir - Optional, defaults to ${PWD}
# Returns:
# 0 on success, storing result to ${jartps1_gitdir}.
# 1 if dir isn't inside a Git repo.
# Globals:
# jartps1_gitdir - Used to store result.
# JARTPS1_GITDIR_TMP - Temp file used to cache last failed search.
################################################################################
jartps1_gitdir_find() {
local dir="$1"
if [[ -z "${dir}" ]]; then
dir="${PWD}"
case "${dir}" in
/) return 1 ;;
/google/*) return 1 ;;
/home/build/*) return 1 ;;
/home/${USER}) return 1 ;;
/usr/local/google/home/${USER}) return 1 ;;
esac
if [[ -f "${JARTPS1_GITDIR_TMP}" ]]; then
local notgit
if read notgit <"${JARTPS1_GITDIR_TMP}" &>/dev/null; then
if [[ "${dir}" == "${notgit}" ]]; then
return 1
fi
fi
fi
fi
if [[ -d "${dir}/.git" ]]; then
jartps1_gitdir="${dir}"
else
local parent="${dir%/*}"
if [[ -z "${parent}" ]]; then
printf "%s" "$PWD" >"${JARTPS1_GITDIR_TMP}"
return 1
fi
jartps1_gitdir_find "${parent}"
fi
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.