Set Your zsh Prompt

Since the beginning of time, all the cool kids have had really cool shell prompts. It's a great place to display helpful information, and zsh has features that let you have a flexible, informative, unobtrusive prompt.

Set your prompt by setting $PROMPT. If you do PROMPT='foo ', the shell will give you a foo prompt for every command. Not terribly useful but you get the point.

There are a bunch of codes you can use in the value of PROMPT to get useful output. For example, %m gives the name of the machine you're running on, and %~ gives the name of the current working directory. For a list of all the codes, check the "zshmisc" man page under the section "SIMPLE PROMPT ESCAPES". Note that there are codes for boldface, underline, and colors here too.

The drawback to having all kinds of information in your prompt is that you limit the length of commands that you can enter without scrolling. Scrolling stinks because the command is harder to read. Enter the "right prompt". Set RPS1 to contain the lengthy part of your prompt, and it will be displayed on the right margin of your terminal. Then when commands get long and encroach on the right prompt, it will conveniently disappear. Read Quentin's comment on this zsh post.

Here's a gotcha with RPS1 and fancy prompt formatting: gnome-terminal does not behave well when these are set. I'm trying out alternatives to see which will be better.

Lastly, a trick I picked up from Justin. Zsh provides hooks that you can use to do things before and after a command runs. Just define the functions preexec and precmd. This example sets the title of the xterm while a command is running:

function title() {
    # escape '%' chars in $1, make nonprintables visible
    local a=${(V)1//\%/\%\%}

    # Truncate command, and join lines.
    a=$(print -Pn "%40>...>$a" | tr -d "\n")
    case $TERM in
        screen*)
            print -Pn "\e]2;$a @ $2\a" # plain xterm title
            print -Pn "\ek$a\e\\"      # screen title (in ^A")
            print -Pn "\e_$2   \e\\"   # screen location
            ;;
        xterm*)
            print -Pn "\e]2;$a @ $2\a" # plain xterm title
            ;;
    esac
}

# precmd is called just before the prompt is printed
function precmd() {
    title "zsh" "%m:%55<...<%~"
}

# preexec is called just before any command line is executed
function preexec() {
    title "$1" "%m:%35<...<%~"
}

Update: Set variable a to local in function title above as suggested in the comment below.

Posted on 2010-02-01 by brian in zsh .

Comments

I ripped that from somewhere else on the net with comments and all. It was by far the best out of a few. I think it was from http://dotfiles.org/ which is a decent resource for quickly obtaining different solutions to common interactive shell problems.

I'm always tempted to make a more flashy $PROMPT with colors and what not, because face it -- you're going to be stuck on busybox at times. It seems like a good idea that custom zsh hosts be easily distinguishable from minimal shells. I still don't do the color prompt though.

Justin
2010-02-25 01:16:32

There's only one problem in that code. When you hapen to use a as variable in the command line it will collide with a defined globally in function title(). Even after turning a into local a you still won't be able to say things like a="x x x// /" .. next line.. echo $a in the console. Any ideas how to fix that besides of renaming a into something less "common" like ZEWTGASDG1233 to avoid potential ambiguities.

kiviuq
2010-03-05 14:35:38

My fault. Actually ambiguities are resolved if a is declared local infunction title(). So putting "local" as an identifier in front of the first occurance of a in function title() and you may again use a as a variable in the command line independently from a in titlel(). Sorry about the confusion. To auto detect global declarations in the future one can add

setopt warncreateglobal

to .zshrc

kiviuq
2010-03-05 15:01:53
Comments on this post are closed. If you have something to share, please send me email.