Back
First published on 12/26/2023.

Zsh Theme Customization

In my effort to make my customize my zsh terminal exactly how I wanted, I found that there weren't many good articles on the topic. So today I'm going to guide you through a few pieces of simple syntax to improve your terminal experience!

My current terminal configuration

Setting up your custom theme

  1. Navigate to your home directory (cd ~).
  2. Open your .zshrc file.
  3. If the file has been set up correctly, there should be a variable called ZSH_THEME. Set this to whatever name you'd like for your new custom theme. Mine is "minimalism" (very creative, I know).
    • If you choose to customize an existing theme instead of creating your own, put the name of that theme here and we can customize it within the file it is defined.
  4. Navigate to the folder ~/.oh-my-zsh/custom/themes/ and create your new theme! Mine is ~/.oh-my-zsh/custom/themes/minimalism.zsh-theme.
    • If you decided to edit an existing theme (which is how I started), find the theme you like in the folder ~/.oh-my-zsh/themes/ and open it up.

Customizing the theme

Basic structure

Our basic structure starts with two variables, PROMPT and RPROMPT. Both are optional and specify what is displayed on the left and the right side of the terminal.

I begin my PROMPT with a line break so that there's always some space before a new command.

1
# minimalism.zsh-theme
2

3
PROMPT='
4
%F{magenta}> %f'

Note that spaces (including line breaks) are interpreted literally, so there is little to be done about improving readability.

Next, as will immediately become apparent, the percent symbol % is a reserved, special character and is central to theming. It is used for styling (e.g. %F{red}text that is red%f) and for reserved content (e.g.%c) (the current directory).

I'll return later to some more advanced content, such as git commands and custom functions.

Basic content

Below is some of the basic content I've come across. It is just as easy as including these in your PROMPT or RPROMPT strings.

Syntax Description
%nusername
%mhost name
%1~current directory. The number references number of files down
%ccurrent directory
%Ttime in 24-hour format
%ttime in AM/PM or 12-hour format
%*time in 24-hour format with seconds

Example

1
# minimalism.zsh-theme
2

3
PROMPT='
4
%* >'

Simple example

Styling

Zsh supports bold, underline, and foreground and background colors. Below is a table of how to implement each.

Syntax Style Example Image
%B ... %bBold%B%n%bZsh bold example
%U ... %uUnderline%U%1~%uZsh underlined example
%S ... %sHighlighted%S%T%sZsh highlighted example
%F{color} ... %fForeground color%F{red}$(git_repo_name)%fZsh foreground example
%K{color} ... %kBackground color%F{red}%K{yellow}%t%f%kZsh background example

Note: In one of my workspaces there is support for hex codes (this might be a feature of iTerm), but on my personal computer, I am reliant upon color keywords. So here is a list of supported color keywords:

black, blink, blue, bold, brown, cyan, darkgray, gray, green, halfbright, lightblue, lightcyan, lightgray, lightgreen, lightmagenta, lightred, magenta, red, reset, reverse, and yellow.

More complex content

Here is a list of all of the git commands you might want access to. I list some examples for how to use them below.

To include a function, like the existing ones in the link above, one passes it to PROMPT or RPROMPT like so:

1
RPROMPT='$(git_current_branch)'

The link above also has a list of prompt variables, which are in screaming snake case (e.g. ZSH_THEME_GIT_PROMPT_DIRTY). These can be defined anywhere in your theme file and often include stylized symbols. For example, I include a number of symbols for if the branch is clean or note.

1
ZSH_THEME_GIT_PROMPT_DIRTY="%F{yellow} ☂%f"
2
ZSH_THEME_GIT_PROMPT_UNTRACKED="%F{cyan} ✭%f"
3
ZSH_THEME_GIT_PROMPT_CLEAN="%F{yellow} ☀%f"

Custom functions

Creating and using your own custom functions is very easy and straightforward! All you need to do is create a function, let's call if custom_function(). Then in one of your PROMPT's, pass it like so: ${$(custom_function)}. This will be run every time on terminal load and after every terminal command, so if the function relies on git, make sure it checks if this is a git repository.

Example

In my current job, my team has a convention for naming our git branches which includes the numbers of the current jira ticket (the task we are working on). To include this in my minimalist terminal, I created the following custom function.

1
RPROMPT='%S%F{yellow}$(current_ticket)%f%s'
2

3
current_ticket() {
4
    # checks if it is a git repository. the '-d' flag checks for folders
5
    if test -d ".git"; then
6
        # gets the current branch and does a regex pattern match
7
        echo -e "$(git_current_branch)" | grep -Eo '[0-9]{4}'
8
    fi
9
}

Example with bonus regex tip

The below example illustrates a function that will either take a feature branch with the format 'feature/1234/Component/description-of-work' and returns everything after the ticket number, or if it is not a feature or bugfix branch (e.g. main), then it returns the entire branch name.

1
RPROMPT='[$(branch_description)]'
2

3
branch_description() {
4
    # checks if it is a git repository.
5
    if test -d ".git"; then
6
        regex='[0-9]{4}\/(.+)'
7
        branch="$(echo -e "$(git_current_branch)")"
8

9
        if [[ $branch =~ $regex ]]
10
        then
11
            echo $branch | grep -Eo '[a-zA-Z-]+\/[a-zA-Z-]+$'
12
        else
13
            echo $branch
14
        fi
15
    fi
16
}

Full example

1
PROMPT='
2
%F{magenta}> %f'
3

4
RPROMPT='[%F{magenta}%c%f]%S%F{yellow}%f%s%F{cyan}${$(branch_description)}%f$(parse_git_dirty)'
5

6
branch_description() {
7
    if test -d ".git"; then
8
        reg='[0-9]{4}\/(.+)'
9
        branch="$(echo -e "$(git_current_branch)")"
10

11
        if [[ $branch =~ $reg ]]
12
        then
13
            echo $branch | grep -Eo '[a-zA-Z-]+\/[a-zA-Z-]+$'
14
        else
15
            echo $branch
16
        fi
17
    fi
18
}
19

20
ZSH_THEME_GIT_PROMPT_DIRTY="%F{yellow} ☂%f"
21
ZSH_THEME_GIT_PROMPT_UNTRACKED="%F{cyan} ✭%f"
22
ZSH_THEME_GIT_PROMPT_CLEAN="%F{yellow} ☀%f"

Terminal example

List of symbols

Below are a list of symbols that were included in the wedisagree theme that I found useful.

☁ ☂ ✭ ☀ Ⓓ ⓣ Ⓞ ⓐ ⓜ ⓧ ⓡ ⓤ ⑃ ⑁ ⑂ ⑄ ⑊ 𝝙 ✹ ☄ ♆ ♀ ♁ ♐ ♇ ♈ ♉ ♚ ♛ ♜ ♝ ♞ ♟ ♠ ♣ ⚢ ⚲ ⚳ ⚴ ⚥ ⚤ ⚦ ⚒ ⚑ ⚐ ♺ ♻ ♼ ☰ ☱ ☲ ☳ ☴ ☵ ☶ ☷ ✡ ✔ ✖ ✚ ✱ ✤ ✦ ❤ ➜ ➟ ➼ ✂ ✎ ✐ ⨀ ⨁ ⨂ ⨍ ⨎ ⨏ ⨷ ⩚ ⩛ ⩡ ⩱ ⩲ ⩵ ⩶ ⨠ ⬅ ⬆ ⬇ ⬈ ⬉ ⬊ ⬋ ⬒ ⬓ ⬔ ⬕ ⬖ ⬗ ⬘ ⬙ ⬟ ⬤ 〒 ǀ ǁ ǂ ĭ Ť Ŧ ╭╰ ─

Conclusion

There is clearly a ton I didn't cover, but this is what I've fine-tuned to show only the things I care about in an aesthetic way. I hope it was helpful!