Theme Me Up, Scotty! - A Beginner's Guide To Zsh Themes

Zsh prompt

So, if like me you spend a lot of your time in front of a terminal, you want it to look good; and who says stylish can’t also be practical?

This guide will focus on themes for Zsh: an extension of the Bourne Shell (sh) with a multitude of useful features. If you want to know more about Zsh and how to switch to it, give this article by How-To Geek a read.

If you've made it this far, I have to assume that you've been convinced by the various benefits of Zsh and have made it your default shell. "But how do I make it look cool?" I hear you ask; the answer is themes.

Oh My Zsh


The easiest way of applying a theme to your Zsh shell is to use Oh My Zsh. Oh My Zsh provides multiple other ways of customising your Zsh shell, not just themes, however, these are outside of the scope of this guide.

To install Oh My Zsh, simply run one of the commands below:

sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
sh -c "$(wget -O- https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"

For the security-conscious among you, the following command downloads the installation script without running it so you can see exactly what it does before executing it:

curl -Lo install.sh https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh

Oh My Zsh comes with several themes pre-installed, which you can read about here. There are also many custom themes published on GitHub which are often collated in repositories like the awesome-zsh-plugins repository. These can be installed by downloading their .zsh-theme files and placing them in the Oh My Zsh custom themes directory, which by default is ~/.oh-my-zsh/custom/themes, and can be enabled by setting the ZSH_THEME variable in your .zshrc file to the theme's name. However, if like me you fail to find one that suits your needs, or if you truly want to make your shell your own, you can write your own theme.

Writing Your Own Zsh Theme


The first step in writing your own Zsh theme is to create a new file with a .zsh-theme extension in the Oh My Zsh custom themes directory (e.g. ~/.oh-my-zsh/custom/themes/mycustomtheme.zsh-theme). Once this is done, you'll want to enable the theme by setting the ZSH_THEME variable in your .zshrc file (e.g. ZSH_THEME="mycustomtheme"). Now you're ready to start writing your theme.

A Simple Prompt


Let's start with a simple prompt. Put the following line into your theme file and save it:

PROMPT='> '
Now open a new terminal running Zsh. You should see something like this:

A basic Zsh prompt


A More Informative Prompt


Now this isn't very exciting, or useful, so let's add some more information. Various pieces of useful information can be added to Zsh themes using syntax such as that shown in the table below:

   Syntax 
  Username
%n
  Hostname
%m
  Status of Previous Command
%?
  Path to Current Directory with ~ Substitution  
 ${PWD/#$HOME/~} 
  12-hour Time
%t
  24-hour Time
%T
  24-hour Time with Seconds
%*
  Date/Time Using a strftime Format String  
%D{string}

Change your code to the following and save the file:

PROMPT='[%D{%H:%M:%S}] %n@%m%:${PWD/#$HOME/~} > '
Now switch back to your terminal. You'll notice that your prompt hasn't changed. This is because you need to tell Zsh to reload the theme. To do this, you can either open a new Zsh session or run the following command:

source ~/.zshrc

This tells Zsh to reload the configuration specified in your .zshrc file, causing it to reload your theme.

You should now see something like this:

A more informative Zsh prompt

As you can see, the code above tells Zsh to display the current time, your username, hostname, and current working directory (replacing your home directory with the ~ character), giving you a prompt similar to Bash's default.

Adding Colour


At this point, you're probably shouting at your screen "But Bash's default prompt has colour!". Well let's add some to our prompt shall we? Zsh themes can use a variety of syntaxes to control colour which I have summarised in the table below:

  Using Colour
Codes
Using String
Values
Using Either String
Values or
Colour Codes
Resetting
Formatting
  Foreground (Text)
  Colour
%{$FG[000]%}
 %{$fg[black]%}  %F{000}
%F{black}
%f
  Background Colour
%{$BG[000]%}
%{$bg[black]%}
%K{000}
%K{black}
%k
  All Formatting
   
%{$reset_color%}

Zsh accepts the following string values for defining colour:

  • black
  • blue
  • cyan
  • green
  • magenta
  • red
  • white
  • yellow

To view accepted colour codes, run the following command:

spectrum_ls

This will produce a list of supported colours and their respective codes in the format shown below:

Sample spectrum_ls output

Change your code to the following:

PROMPT='%{$FG[007]%}[%D{%H:%M:%S}] %{$FG[014]%}%n@%m%{$FG[015]%}:%{$FG[007]%}${PWD/#$HOME/~}%{$FG[015]%} > %{$reset_color%}'
Now reload your theme and you should see something like this:

Zsh prompt with colour

Choosing the right colour scheme for you can take some trial and error, however, reloading your theme after every change to see how it looks can be tedious. To avoid this, you can use the print -P command to see what your prompt will look like as shown below:

Example print -P output

Once you've found a colour scheme that you like, simply set the PROMPT variable in your theme file accordingly and reload your theme.

Adding Formatting


Zsh also allows you to format your text. As with colour, you can use a variety of sytaxes to add formatting to your prompt which I have again summarised in a table below:

   Applying
Formatting
Resetting
Formatting
  Bold
%{$FX[bold]%}
%B
 %{$fg_bold[black]%} 
%{$FX[no-bold]%}
%b

  Italic
 %{$FX[italic]%} %{$FX[no-italic]%}
  Underline
 %{$FX[underline]%}
%U
 %{$FX[no-underline]%} 
%u
  Standout %S %s
  Blink
 %{$FX[blink]%}  %{$FX[no-blink]%}
  All Formatting  
   %{$reset_color%}

Change your code to the following:

PROMPT='%{$FG[007]%}[%D{%H:%M:%S}] %{$FX[bold]$FG[014]%}%n@%m%{$FX[no-bold]$FG[015]%}:%{$FX[italic]$FG[007]%}${PWD/#$HOME/~}%{$FX[no-italic]$FG[015]%} > %{$reset_color%}'
When you reload your theme, you should see something like this:

Zsh prompt with formatting

Note: As with colours, the prompt -P command can be used to test out your formatting without having to reload your theme.

Adding Logic


So a useful feature of .zsh-theme files is that they are basically just shell scripts, which means you can add logic to them. For example, as a pentester, I often find myself switching between my user account and the root account on my machine. Now as our theme stands in its current form, I'd have to read the prompt to see which user I'm currently using, but what if I could easily tell with just a glance? Change your code to the following:

local user_colour='014'; [ $UID -eq 0 ] && user_colour='027'
PROMPT='%{$FG[007]%}[%D{%H:%M:%S}] %{$FX[bold]$FG[$user_colour]%}%n@%m%{$FX[no-bold]$FG[015]%}:%{$FX[italic]$FG[007]%}${PWD/#$HOME/~}%{$FX[no-italic]$FG[015]%} > %{$reset_color%}'

You'll notice that at first, this doesn't appear to have changed anything, however, run Zsh as the root user and you should see something like this:

Zsh prompt with logic

As you can see, the theme now changes the colour of the username and hostname if you're logged in as the root user, making it obvious which user you are currently using at a quick glance.

Note: In order for the sudo su command to have the effect shown in the example, Zsh must be set as the default shell for the root account and your theme must be specified in root's .zshrc file.

Updating Your Prompt in Real-Time


You may have noticed that up until now, your prompt is not updated once it has been generated. This can be inconvenient if you're using features like timestamps as your prompt will indicate their status at the time of generation and not at the current time. To combat this problem, you can tell Zsh to regenerate your prompt at regular intervals. To do this, add the following code to your .zsh-theme file:

TMOUT=1
TRAPALRM() {
zle reset-prompt
}


This will tell Zsh to regenerate your prompt every second, keeping features like your timestamp accurate.

Note: This won't cause you to lose any text you have already typed into your terminal, so you don't have to worry about having to type your commands insanely fast!

Incorporating Git Information


A popular feature of Zsh themes is their ability to display Git information. This can be achieved by integrating some pre-defined functions and variables into your theme. Zsh has the following pre-defined functions available to display git information:

  • git_prompt_status
  • git_prompt_info

The following pre-defined variables can be used to modify what these functions return:

  • ZSH_THEME_GIT_COMMITS_AHEAD_PREFIX
  • ZSH_THEME_GIT_COMMITS_AHEAD_SUFFIX
  • ZSH_THEME_GIT_PROMPT_ADDED
  • ZSH_THEME_GIT_PROMPT_AHEAD
  • ZSH_THEME_GIT_PROMPT_AHEAD_REMOTE
  • ZSH_THEME_GIT_PROMPT_AHEAD_REMOTE_COLOR
  • ZSH_THEME_GIT_PROMPT_BEHIND
  • ZSH_THEME_GIT_PROMPT_BEHIND_REMOTE
  • ZSH_THEME_GIT_PROMPT_BEHIND_REMOTE_COLOR
  • ZSH_THEME_GIT_PROMPT_CLEAN
  • ZSH_THEME_GIT_PROMPT_DELETED
  • ZSH_THEME_GIT_PROMPT_DIRTY
  • ZSH_THEME_GIT_PROMPT_DIVERGED
  • ZSH_THEME_GIT_PROMPT_DIVERGED_REMOTE
  • ZSH_THEME_GIT_PROMPT_MODIFIED
  • ZSH_THEME_GIT_PROMPT_PREFIX
  • ZSH_THEME_GIT_PROMPT_REMOTE_EXISTS
  • ZSH_THEME_GIT_PROMPT_REMOTE_MISSING
  • ZSH_THEME_GIT_PROMPT_REMOTE_STATUS_DETAILED
  • ZSH_THEME_GIT_PROMPT_REMOTE_STATUS_PREFIX
  • ZSH_THEME_GIT_PROMPT_REMOTE_STATUS_SUFFIX
  • ZSH_THEME_GIT_PROMPT_RENAMED
  • ZSH_THEME_GIT_PROMPT_SHA_AFTER
  • ZSH_THEME_GIT_PROMPT_SHA_BEFORE
  • ZSH_THEME_GIT_PROMPT_STAGED
  • ZSH_THEME_GIT_PROMPT_STASHED
  • ZSH_THEME_GIT_PROMPT_SUFFIX
  • ZSH_THEME_GIT_PROMPT_UNMERGED
  • ZSH_THEME_GIT_PROMPT_UNSTAGED
  • ZSH_THEME_GIT_PROMPT_UNTRACKED

The best way to understand what these do is to look at their use in existing themes and to play around with them. When used effectively, these functions and variables can modify your prompt to display various Git information when your current working directory lies within a Git repository. For example, you may see something like this:

Zsh prompt with Git information

This example shows the current branch and the various statuses of the files within a Git repository.

It should be noted that in this example, the Git information appears on the right-hand side of the terminal. This was achieved by using the RPROMPT variable, which works in the same way as the PROMPT variable, however, it is displayed on the right-hand side of the terminal.

Conclusion


This guide is not the be-all and end-all of Zsh theme knowledge, however, it should be more than enough to get you started in the wonderful world of Zsh themes.

If you like the theme used in the examples, you can download the full version from my GitHub here.

Happy theming!

No comments:

Post a Comment

Popular Posts