Thursday, 30 December 2010

The Perfect Prompt

Long ago I switched to zsh from bash for my hacking needs. I think at the time I just needed a new toy. However, over the years, zsh has proven to be a very good shell, with excellent flexibility, a healthy "Do what I Mean" attitude, and overall much more powerful globbing, auto-complete, keybinding and scripting capabilities than bash.

Part of the usual appeal of zsh are the ridiculously fancy prompts you can make it display. I was never a fan of those. My prompts have to be simple, since I'm staring at them all the time. Don't show me anything I don't need, to know! I find it hard to concentrate on something anyway, without my shell telling me how many emails I have left in my Inbox. So I created the perfect minimalist prompt that does exactly what I need it to do:
  • Display whether I'm root or not
  • How many jobs are there running in the background (if any?)
  • Did the last command finish successfully, or did the damn thing just die silently?
  • Since I'm using vi keybindings, am I in insert mode or in normal mode?
  • What machine is this shell on?
  • What directory is this shell in?
Almost all of these have defaults I don't expect to be mentioned. Usually, I have nothing running in the background, I'm on my local machine, and the last command finished successfully. At that point, I don't need to be reminded that all is well. Hide it! So here's a picture: Let's go over the features one-by one:

I don't like directories to be on the left-hand side prompt, since that'll move your prompt all the way to the right when you're in a deeply nested directory. So they're on the right, where they don't bother me, but I can still look them up easily (the blue string on the right will disappear if the cursor gets too close.)

Named directories are zsh's handy way to provide directory shortnames. Instead of going to the lengthy ~/Documents/src I can just go to ~src. I can define similar hashes for projects I'm working on, say ~myproject for ~/Documents/src/java/myproject.

Whenever there's a background job (like sleep in this example) I get a yellow number before my prompt mark. This is a counter for the background jobs. It disappears if there aren't any.

The shell checks the variable SSH_CLIENT to see if it's on a remote or local machine. On a local machine, nothing happens, but on a remote machine (i.e. a machine I'm accessing via SSH — the client always sets SSH_CLIENT when connecting) it displays the leftmost part of the machine's subdomain. I don't need to know I'm on a local machine when I'm sitting in front of it! But I do want to know if a shell doesn't belong to the machine I'm currently working on.

Similarly to the background job display, I don't want to always know every program's return code. I'm interested in the ones that failed. If a program returns non-zero, I see a big fat red number signalizing error.

Finally I like to know which mode I'm in. The blue > indicates insert mode, and a yellow indicates normal mode. Like this:

Since it's tracked by version control, I'll link you to my .zshrc. My shell config changes periodically, and no doubt even this "perfect prompt" will experience revisions. Use the commit log to find commits to .zshrc that look like this one.

Finally, since my config's rather big, maybe someone will find something else useful there :-)

No comments: