|
|
--- |
|
|
title: Building a ZSH prompt |
|
|
tags: |
|
|
- Linux |
|
|
- ZSH |
|
|
description: There are many frameworks out there to help you build a prompt, I thought I'd see how far I could get without one. |
|
|
date: 2020-03-24 |
|
|
draft: true |
|
|
--- |
|
|
|
|
|
Until recently, I was using [oh-my-zsh](https://github.com/ohmyzsh/ohmyzsh) with the [Power Level 9k](https://github.com/Powerlevel9k/powerlevel9k) prompt. |
|
|
|
|
|
In part of my effort to understand how different parts of my system works, and to reduce my reliance on some libraries, I decided to see if I could get what I needed without them. In this blog post, I am going to focus on my prompt configuration. |
|
|
|
|
|
If you want to follow along, my configuration can be found in [my dotfiles](https://github.com/Jab2870/dotfiles/blob/master/shells/zsh/includes/promptconfig.zsh). |
|
|
|
|
|
My prompt currently looks something like this: |
|
|
|
|
|
![My Prompt](/assets/prompt/prompt.png) |
|
|
|
|
|
## Basics |
|
|
|
|
|
Zsh simply prints the variables `PROMPT` and `RPROMPT` when drawing the left and right prompts respectively. `PROMPT` is roughly equivalent to the `PS1` variable in bash. |
|
|
|
|
|
By setting the variable, you can change how the prompt works. E.g. |
|
|
|
|
|
``` |
|
|
oldPrompt $ PROMPT="new prompt > " |
|
|
new prompt > ls |
|
|
Documents Downloads GitRepos |
|
|
new prompt > █ |
|
|
``` |
|
|
|
|
|
## ZSH Hooks |
|
|
|
|
|
Zsh has a concept called hooks. These allow you to run a function (or functions) automatically at certain times. |
|
|
|
|
|
For the purposes of setting my prompt, I want to run a function to set `PROMPT` and `RPROMPT` before the prompt is drawn. This can be done with the `precmd` hook. |
|
|
|
|
|
```zsh |
|
|
set_prompts(){ |
|
|
PROMPT="$ " |
|
|
RPROMPT="" |
|
|
} |
|
|
zle -N set_prompts |
|
|
autoload -U add-zsh-hook |
|
|
add-zsh-hook precmd set_prompts |
|
|
``` |
|
|
|
|
|
This defines a function `set_prompts` and it will be run just before the prompt is drawn, every time. We can therefore use it to build the prompt. |
|
|
|
|
|
## Drawing segments |
|
|
|
|
|
I like the arrow style that was made popular by [Powerline](https://github.com/powerline/powerline). To achieve this, you will need a font that contains the powewline glyphs. If you don't have one, I highly recommend the [Nerd Fonts](https://www.nerdfonts.com/) project that aggregates a lot of icons as well as the powerline symbols. It even includes a script that allows you to add them to your favourite font. |
|
|
|
|
|
|
|
|
|
|
|
## Exit Code |
|
|
|
|
|
In ZSH (and most other shells), the exit code of the previous command is available in the special `$?` variable. If we want the exit code of the last command run, we need to assign this to a variable first. |
|
|
|
|
|
```bash |
|
|
# Get the return status of the previous command |
|
|
local RETVAL=$? |
|
|
``` |
|
|
|
|
|
## Git |
|
|
|
|
|
I use Git a lot. It is useful to tell, at a glance, which branch I'm on, which tag I'm on and what the state of repository is. The function is quite simple: |
|
|
|
|
|
```bash |
|
|
prompt_git(){ |
|
|
local repoTopLevel="$(command git rev-parse --show-toplevel 2> /dev/null)" |
|
|
if [ -n "$repoTopLevel" ]; then |
|
|
local branch="$(git branch --show-current 2> /dev/null)" |
|
|
local tag="$(git describe --tags --exact-match HEAD 2> /dev/null)" |
|
|
local color="green" |
|
|
local ret="" |
|
|
[ -n "$branch" ] && ret="$branch " |
|
|
[ -n "$tag" ] && ret+="$tag " |
|
|
[ -n "$ret" ] || ret="$(git rev-parse --short HEAD 2> /dev/null)" |
|
|
local repoTopLevel="$(command git rev-parse --show-toplevel 2> /dev/null)" |
|
|
local untrackedFiles=$(command git ls-files --others --exclude-standard "${repoTopLevel}" 2> /dev/null) |
|
|
local modified=$(command git diff --name-only 2> /dev/null) |
|
|
local staged=$(command git diff --staged --name-only 2> /dev/null) |
|
|
|
|
|
if [ -n "$untrackedFiles" ]; then |
|
|
ret+=" " |
|
|
color="orange1" |
|
|
fi |
|
|
if [ -n "$modified" ]; then |
|
|
ret+=" " |
|
|
color="orange1" |
|
|
fi |
|
|
if [ -n "$staged" ]; then |
|
|
ret+=" " |
|
|
color="orange1" |
|
|
fi |
|
|
fi |
|
|
ret="$(echo "$ret" | sed -e 's/ *$//')" |
|
|
echo "$ret" |
|
|
echo "$color" |
|
|
} |
|
|
``` |
|
|
|
|
|
|