My prompt has expanded and contracted over the years. When developing more in Ruby and Python, I found it very important to keep my current language versions in the prompt, but these days it’s more important to me that my prompt works on every Unix-based machine I might log on to.
I keep my prompt setup in a file called prompt.sh
, of course.
Here’s what my prompt looks like after running a command for 10 seconds that resulted in an error:
On the first line, I have my current directory then my current Git branch, if I’m in a Git repository. Note the asterisk beside the Git branch: that means that I have uncommitted changes. Next, I have the amount of time the previous command took. This only shows up if the amount of time it took was 5 or more seconds; below that, it’s not that important to know. Lastly, I have the exit status of the last command. I only show this if the exit status is not zero; that is, if there was an error.
To get the Git branch and the change status, I have these two functions:
function parse_git_dirty() {
[[ $(git status 2> /dev/null | tail -n1) != *"nothing to commit"* ]] && echo "*"
}
function parse_git_branch() {
local git_branch=$(git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e "s/* \(.*\)/\1$(parse_git_dirty)/")
[[ -z $git_branch ]] || echo " $git_branch"
}
This is all pretty simple stuff. To get the branch, I run git branch
and then use sed
to get the line that starts with *
and strip the *
out. I append an asterisk to that if I know the repo is dirty (that is, there are uncommitted changes.) What’s interesting here is that I pipe STDOUT
to /dev/null
in both these cases, and count on failure – which will only happen if I’m not in a Git repo – to produce no text. There is no test to see if I’m in a repo: I just go ahead and try it and print nothing on error.
The timer code is way more interesting:
function timer_start() {
timer=${timer:-$SECONDS}
}
function timer_stop() {
timer_show=$(($SECONDS - $timer))
unset timer
}
function prompt_command() {
# ...
timer_stop
#...
}
PROMPT_COMMAND=prompt_command
trap timer_start DEBUG
SECONDS
increases monotonically like you’d expect: add 1 every second. trap timer_start DEBUG
is a neat piece of code. trap
means “run the following function on the following signal,” and the signal DEBUG
is triggered every time a command is run. So, every time a command is run, timer_start
is run. timer_start
sets timer
to $SECONDS
if it’s not currently set. The function assigned to PROMPT_COMMAND
, which is called prompt_command
in this case, is run every time the prompt is printed. Inside prompt_command
, I execute timer_stop
, which sets the variable timer_show
equal to the timer subtracted from the current value of SECONDS
. I can use timer_show
, which has the calculated value of the amount of time it took to run the last command, when displaying the prompt.
The rest of what I do, printing error codes and setting colors, is all simple stuff that you can pick up from reading the file.
When I first set up my current prompt, I colored the $
character on the second line of my prompt. It looked nice, but I found that the characters printed to set the color, normally invisible, sometimes caused the command at the prompt to shift to the right when scrolling up through history.