Skip to content

Terminal & Shell Setup

Ghostty with zsh and acecat theme Ghostty with zsh and acecat theme, remote and root

Ghostty

I've started using Mitchell Hashimoto's Ghostty, it's fast, clean and runs natively on both macOS and Linux.

Ghostty is a fast, feature-rich, and cross-platform terminal emulator that uses platform-native UI and GPU acceleration.

Configuration

theme = catppuccin-mocha
font-family = "MesloLGM Nerd Font"
keybind = global:cmd+grave_accent=toggle_quick_terminal

Ghostty on macOS has a Quick Terminal, I've set a global keybinding of Cmd+` so I can access it from anywhere.

Ghossty quick terminal

Optional: VS Code Settings

VS Code users will need to add the following to their settings.json:

"terminal.external.osxExec": "Ghostty.app",
"terminal.integrated.fontFamily": "MesloLGM Nerd Font",

Z shell (zsh)

Required software:

brew install bat eza fzf jandedobbeleer/oh-my-posh/oh-my-posh

Some distros have recent enough versions of bat, eza, and fzf, so you can just use your package manager to install them. For Debian/Ubuntu, I wrote a script to do a system-wide install for you:

curl -s https://andrew.lecody.com/guides/terminal-and-shell-setup/prep_debian.sh | bash -s

The script can be run again to upgrade bat, eza, and fzf to the latest versions. Please note, it has to be run as root. If you want to improve it, please send me a pull request.

Next, you'll need to install oh-my-posh using their script:

curl -s https://ohmyposh.dev/install.sh | bash -s

This script can also be run again for upgrades.

Note

Ghostty has Nerd Fonts built-in, so if you use another terminal emulator you will need to install the Meslo font yourself.

Automatic Install

curl -s https://andrew.lecody.com/guides/terminal-and-shell-setup/install.sh | bash -s

Files

Here are the files, if you just want to look at them instead of running my install script.

install.sh
#!/usr/bin/env bash

set -e

REQUIRED_PROGRAMS=(
  wget
  curl
  git
  bat
  fzf
  eza
  oh-my-posh
)

[[ "$OSTYPE" == darwin* ]] && REQUIRED_PROGRAMS+=(brew)

MISSING_PROGRAMS=()

# Check each command
for cmd in "${REQUIRED_PROGRAMS[@]}"; do
  if ! command -v "$cmd" &> /dev/null; then
    MISSING_PROGRAMS+=("$cmd")
  fi
done

# If any commands are missing, list them and exit
if [ ${#MISSING_PROGRAMS[@]} -ne 0 ]; then
  echo "Error: Missing required programs:"
  printf '%s\n' "${MISSING_PROGRAMS[@]}"
  exit 1
fi

# Some systems will call compinit before evaluating ~/.zshrc and we don't want that.
# On these systems we need to add "skip_global_compinit=1" to ~/.zshenv
[ -f /etc/zsh/zshrc ] && grep -q "skip_global_compinit=1" /etc/zsh/zshrc && \
  (grep -q "^skip_global_compinit=1$" ~/.zshenv 2>/dev/null || \
  (echo "skip_global_compinit=1" >> ~/.zshenv && echo "Updated ~/.zshenv"))

echo "Installing plugins to ~/.local/share"
ZSH_PLUGINS=(
  mattmc3/ez-compinit
  lukechilds/zsh-nvm
)
if [[ "$OSTYPE" == darwin* ]]; then
  # On macOS I prefer installing these using brew
  brew install zsh-autosuggestions zsh-syntax-highlighting
else
  ZSH_PLUGINS+=(zsh-users/zsh-syntax-highlighting zsh-users/zsh-autosuggestions)
fi
for REPO in "${ZSH_PLUGINS[@]}"; do
  echo "$REPO"
  DIRECTORY="$HOME/.local/share/$(basename "$REPO")"
  if [ -d "${DIRECTORY}" ]; then
    cd "${DIRECTORY}"
    git pull
    cd -
  else
    git clone --depth 1 "https://github.com/$REPO" "${DIRECTORY}" >/dev/null
  fi
done

echo "Installing themes to ~/.local/share/themes"
THEME_URLS=(
  https://andrew.lecody.com/guides/terminal-and-shell-setup/acecat.omp.toml
  https://github.com/catppuccin/zsh-syntax-highlighting/raw/main/themes/catppuccin_mocha-zsh-syntax-highlighting.zsh
  https://github.com/catppuccin/delta/raw/main/catppuccin.gitconfig
)
mkdir -p ~/.local/share/themes
for THEME_URL in "${THEME_URLS[@]}"; do
  THEME_FILENAME=$(basename "$THEME_URL")
  echo "$THEME_FILENAME"
  wget -q -c "$THEME_URL" -O ~/.local/share/themes/"$THEME_FILENAME"
done

BAT_THEMES_DIR="$(bat --config-dir)/themes"
echo "Installing Catppuccin Mocha theme for bat"
mkdir -p "$BAT_THEMES_DIR"
wget -q -c https://github.com/catppuccin/bat/raw/main/themes/Catppuccin%20Mocha.tmTheme -O "$BAT_THEMES_DIR/Catppuccin Mocha.tmTheme"
bat cache --build

curl -s https://andrew.lecody.com/guides/terminal-and-shell-setup/generate_completions > ~/.local/bin/generate_completions
chmod +x ~/.local/bin/generate_completions

[ -f ~/.zshrc ] && mv ~/.zshrc ~/.zshrc-"$(date +%s)"
curl -s https://andrew.lecody.com/guides/terminal-and-shell-setup/zshrc > ~/.zshrc

[ -f ~/.zsh_aliases ] && mv ~/.zsh_aliases ~/.zsh_aliases-"$(date +%s)"
curl -s https://andrew.lecody.com/guides/terminal-and-shell-setup/zsh_aliases > ~/.zsh_aliases

[ -f ~/.zsh_functions ] && mv ~/.zsh_functions ~/.zsh_functions-"$(date +%s)"
curl -s https://andrew.lecody.com/guides/terminal-and-shell-setup/zsh_functions > ~/.zsh_functions

echo "Testing the zsh setup, you may see nvm get setup during this."
zsh -i -c 'exit'

echo "Generating completion files, this avoids having to generate them each time we start a session."
~/.local/bin/generate_completions
prep_debian.sh
#!/usr/bin/env bash

set -e

GREY='\033[0;30m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BOLD_RED='\033[1;31m'
BOLD_YELLOW='\033[1;33m'
BG_BLUE='\033[44m'
RESET='\033[0m'

REQUIRED_PROGRAMS=(
  curl
  lsb_release
  jq
)

MISSING_PROGRAMS=()

# Check each command
for cmd in "${REQUIRED_PROGRAMS[@]}"; do
  if ! command -v "$cmd" &> /dev/null; then
    MISSING_PROGRAMS+=("$cmd")
  fi
done

# If any commands are missing, list them and exit
if [ ${#MISSING_PROGRAMS[@]} -ne 0 ]; then
  echo -e "${BOLD_RED}Error:${RESET} Missing required programs:"
  printf '%s\n' "${MISSING_PROGRAMS[@]}"
  exit 1
fi

# Check if the distribution is Debian or Ubuntu
DISTRO=$(lsb_release --id --short)
if [[ "${DISTRO}" != "Debian" && "${DISTRO}" != "Ubuntu" ]]; then
    echo -e "${BOLD_YELLOW}Sorry, this script only works for Debian/Ubuntu${RESET}"
    exit 1
fi

# Check if this is an x86_64 system
ARCH=$(uname --machine)
case "$ARCH" in
  x86_64)  ARCH_ALT="amd64";;
  aarch64) ARCH_ALT="arm64";;
  *)
    echo -e "${BOLD_YELLOW}Sorry, this script only works for x86_64 (amd64) and aarch64 (arm64)${RESET}"
    exit 1
esac

# Check if we're root
if [ "$(id -u)" -ne 0 ]; then
    echo -e "${BOLD_YELLOW}This script must be run as root, you trust me, right?${RESET}" >&2
    exit 1
fi

get_latest_github_release() {
    local REPO LATEST_VERSION
    REPO="$1"

    if [[ -z "${REPO}" ]]; then
        echo "Usage: get_latest_github_release <username/repository>" >&2
        return 1
    fi

    # Fetch the latest release using GitHub API
    LATEST_VERSION=$(curl -s "https://api.github.com/repos/$REPO/releases/latest" | jq -r '.tag_name')

    # Check if the API call was successful
    if [[ "${LATEST_VERSION}" == "null" || -z "${LATEST_VERSION}" ]]; then
        echo -e "${BOLD_RED}Error:${RESET} Could not fetch the latest release for ${REPO}" >&2
        return 1
    fi

    # Remove 'v' prefix if present
    echo "${LATEST_VERSION#v}"
    return 0
}

install_eza() {
    local VERSION TMPDIR
    VERSION="$1"

    if [[ -z "${VERSION}" ]]; then
        echo "Usage: install_eza <version>" >&2
        return 1
    fi

    if command -v eza &> /dev/null; then
        INSTALLED_VERSION=$(eza --version | sed -n 's/^v\([0-9]\+\.[0-9]\+\.[0-9]\+\).*/\1/p')
        if [[ "${VERSION}" == "${INSTALLED_VERSION}" ]]; then
            echo -e "${YELLOW}Nothing to do${RESET}, the installed version of ${BG_BLUE}eza${RESET} is already ${BG_BLUE}${INSTALLED_VERSION}${RESET}"
            return 0
        fi
    fi

    echo -e "\nInstalling eza ${GREEN}v${VERSION}${RESET}"

    # Download and extract the files to a tmp directory
    TMPDIR=$(mktemp --directory)
    curl -s -L "https://github.com/eza-community/eza/releases/download/v${VERSION}/eza_${ARCH}-unknown-linux-gnu.tar.gz" | tar -C "${TMPDIR}" -zxf -
    curl -s -L "https://github.com/eza-community/eza/releases/download/v${VERSION}/completions-${VERSION}.tar.gz" | tar -C "${TMPDIR}" -zxf -
    curl -s -L "https://github.com/eza-community/eza/releases/download/v${VERSION}/man-${VERSION}.tar.gz" | tar -C "${TMPDIR}" -zxf -

    # Install the files
    echo -e "${GREY}"
    set -x
    install --mode=0755 --owner=root --group=root "${TMPDIR}/eza" /usr/local/bin/eza
    cp "${TMPDIR}/target/completions-${VERSION}/_eza" /usr/local/share/zsh/site-functions/_eza
    mkdir -p /usr/local/share/man/man1 /usr/local/share/man/man5
    cp "${TMPDIR}/target/man-${VERSION}/"*.1 /usr/local/share/man/man1/
    cp "${TMPDIR}/target/man-${VERSION}/"*.5 /usr/local/share/man/man5/
    rm -rf "${TMPDIR}"
    set +x
    echo -e "${RESET}"

    echo -e "Installed at: ${BG_BLUE}$(command -v eza)${RESET}"
    eza --version
}

install_fzf() {
    local VERSION TMPDIR
    VERSION="$1"

    if [[ -z "${VERSION}" ]]; then
        echo "Usage: install_fzf <version>" >&2
        return 1
    fi

    if command -v fzf &> /dev/null; then
        INSTALLED_VERSION=$(fzf --version | sed -n 's/^\([0-9]\+\.[0-9]\+\.[0-9]\+\).*/\1/p')
        if [[ "${VERSION}" == "${INSTALLED_VERSION}" ]]; then
            echo -e "${YELLOW}Nothing to do${RESET}, the installed version of ${BG_BLUE}fzf${RESET} is already ${BG_BLUE}${INSTALLED_VERSION}${RESET}"
            return 0
        fi
    fi

    echo -e "\nInstalling fzf ${GREEN}v${VERSION}${RESET}"

    # Download and extract the file to a tmp directory
    TMPDIR=$(mktemp --directory)
    curl -s -L "https://github.com/junegunn/fzf/releases/download/v${VERSION}/fzf-${VERSION}-linux_${ARCH_ALT}.tar.gz" | tar -C "${TMPDIR}" -zxf -

    # Install the file
    echo -e "${GREY}"
    set -x
    install --mode=0755 --owner=root --group=root "${TMPDIR}/fzf" /usr/local/bin/fzf
    rm -rf "${TMPDIR}"
    set +x
    echo -e "${RESET}"

    echo -e "Installed at: ${BG_BLUE}$(command -v fzf)${RESET}"
    fzf --version
}

install_bat() {
    local VERSION TMPDIR
    VERSION="$1"

    if [[ -z "${VERSION}" ]]; then
        echo "Usage: install_bat <version>" >&2
        return 1
    fi

    if command -v bat &> /dev/null; then
        INSTALLED_VERSION=$(bat --version | sed -n 's/^bat \([0-9]\+\.[0-9]\+\.[0-9]\+\).*/\1/p')
        if [[ "${VERSION}" == "${INSTALLED_VERSION}" ]]; then
            echo -e "${YELLOW}Nothing to do${RESET}, the installed version of ${BG_BLUE}bat${RESET} is already ${BG_BLUE}${INSTALLED_VERSION}${RESET}"
            return 0
        fi
    fi

    echo -e "\nInstalling bat ${GREEN}v${VERSION}${RESET}"

    # Download and extract the file to a tmp directory
    TMPDIR=$(mktemp --directory)
    curl -s -L "https://github.com/sharkdp/bat/releases/download/v${VERSION}/bat_${VERSION}_${ARCH_ALT}.deb" > "${TMPDIR}/bat_${VERSION}_${ARCH_ALT}.deb"

    # Install the package
    echo -e "${GREY}"
    set -x
    dpkg --install "${TMPDIR}/bat_${VERSION}_${ARCH_ALT}.deb"
    rm -rf "${TMPDIR}"
    set +x
    echo -e "${RESET}"

    echo -e "Installed at: ${BG_BLUE}$(command -v bat)${RESET}"
    bat --version
}

install_eza "$(get_latest_github_release eza-community/eza)"
install_fzf "$(get_latest_github_release junegunn/fzf)"
install_bat "$(get_latest_github_release sharkdp/bat)"

echo -e "\nāœ… ${GREEN}All programs were installed successfully!${RESET} šŸš€"
zshrc
# Notes:
#   Some files/programs are considered REQUIRED, so I intentionally do not check for their existence before sourcing/loading.
#   This will make it make it immediately obvious when something is missing, instead of features randomly not working.

# Set ZSH_DEBUGRC to profile startup times, e.g.
# time ZSH_DEBUGRC=1 zsh -i -c exit
# https://www.dotruby.com/articles/profiling-zsh-setup-with-zprof
if [[ -n "$ZSH_DEBUGRC" ]]; then
  zmodload zsh/zprof
fi

# better command history
HISTSIZE=10000
SAVEHIST=$HISTSIZE
HISTFILE=~/.zsh_history
setopt histignoredups extendedhistory

export PATH="$HOME/.local/bin:$PATH"

# faster way to initialize completion system, and some nice styles
# https://github.com/mattmc3/ez-compinit
# Available completion styles: gremlin, ohmy, prez, zshzoo
# You can add your own too. To see all available completion styles
# run 'compstyle -l'
zstyle ':plugin:ez-compinit' 'compstyle' 'zshzoo'
source ~/.local/share/ez-compinit/ez-compinit.plugin.zsh

# automatically escapes characters in unquoted URLs
autoload -Uz url-quote-magic
zle -N self-insert url-quote-magic
# bracketed-paste-magic is required for url-quote-magic
autoload -Uz bracketed-paste-magic
zle -N bracketed-paste bracketed-paste-magic

# This speeds up pasting w/ autosuggest
# https://github.com/zsh-users/zsh-autosuggestions/issues/238
pasteinit() {
  OLD_SELF_INSERT=${${(s.:.)widgets[self-insert]}[2,3]}
  zle -N self-insert url-quote-magic
}
pastefinish() {
  zle -N self-insert $OLD_SELF_INSERT
}
zstyle :bracketed-paste-magic paste-init pasteinit
zstyle :bracketed-paste-magic paste-finish pastefinish

# bat config
export BAT_THEME="Catppuccin Mocha"
# use bat for viewing man pages
export MANPAGER="sh -c 'sed -u -e \"s/\\x1B\[[0-9;]*m//g; s/.\\x08//g\" | bat -p -lman'"
# helpful aliases/functions for using bat
alias bathelp="bat --language=help --style=plain"
help() {
  "$@" --help 2>&1 | bathelp
}
# TODO: make this work with commands like `curl --help all`
# alias -g -- --help="--help 2>&1 | bathelp"

# fzf keybindings and fuzzy search
source <(fzf --zsh)
# catppuccin mocha theme for fzf
export FZF_DEFAULT_OPTS=" \
--color=bg+:#313244,bg:#1e1e2e,spinner:#f5e0dc,hl:#f38ba8 \
--color=fg:#cdd6f4,header:#f38ba8,info:#cba6f7,pointer:#f5e0dc \
--color=marker:#b4befe,fg+:#cdd6f4,prompt:#cba6f7,hl+:#f38ba8 \
--color=selected-bg:#45475a \
--multi"

# zsh-autosuggest config
ZSH_AUTOSUGGEST_STRATEGY=(history completion)
ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=20
ZSH_AUTOSUGGEST_CLEAR_WIDGETS+=(bracketed-paste)

# catppuccin theme for zsh-syntax-highlighting
source ~/.local/share/themes/catppuccin_mocha-zsh-syntax-highlighting.zsh

# Brew should be setting HOMEBREW_PREFIX automatically via ~/.zprofile
case "$OSTYPE" in
  darwin*)  SHARE_DIR="$HOMEBREW_PREFIX/share";;
  *)        SHARE_DIR="$HOME/.local/share";;
esac
source "$SHARE_DIR/zsh-autosuggestions/zsh-autosuggestions.zsh"
source "$SHARE_DIR/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh"

# NodeJS (nvm)
# Using zsh-nvm for lazy loading nvm
# https://github.com/lukechilds/zsh-nvm
export NVM_LAZY_LOAD=true
export NVM_COMPLETION=true
[ -f ~/.local/share/zsh-nvm/zsh-nvm.plugin.zsh ] && source ~/.local/share/zsh-nvm/zsh-nvm.plugin.zsh

# use eza instead of ls
alias ls="eza"
alias l="eza --long --binary --classify=auto" # list, binary size, type indicator (e.g. `/` for dirs)
alias ll="l --all" # list, all
alias llm="ll --sort=modified" # list, all, sort by modification date
alias lls="ll --sort=size" # list, all, sort by size
alias la="eza -lbhHigUmuSa" # list, all, verbose
alias lx="eza -lbhHigUmuSa@" # list, all, verbose, and xattrs
alias tree="eza --tree" # tree
alias lS="eza -1" # display one entry per line

# load our aliases and functions
[ -f ~/.zsh_aliases ] && source ~/.zsh_aliases
[ -f ~/.zsh_functions ] && source ~/.zsh_functions

zshspeed() {
  for i in $(seq 1 10); do
    time zsh -i -c exit
  done
}

# THESE LINES MUST ALWAYS BE AT THE BOTTOM OF THIS FILE!
eval "$(oh-my-posh init zsh --config ~/.local/share/themes/acecat.omp.toml)"
if [[ -n "$ZSH_DEBUGRC" ]]; then
  zprof
fi
zsh_aliases
# ZFS
alias zls="zfs list -o type,name,available,used,logicalused,usedbysnapshots,compressratio,mountpoint"
alias zsl="zfs list -t snapshot"

# SSH
alias s="ssh -l root"
zsh_functions
# get all kubernetes resources for a namespace
kubectlgetall() {
  if [ -z "$1" ]; then
    echo "Usage: $0 <namespace>"
    return 1
  fi
  for i in $(kubectl api-resources --verbs=list --namespaced -o name | grep -v "events.events.k8s.io" | grep -v "events" | sort | uniq); do
    echo "Resource:" $i
    kubectl -n ${1} get --ignore-not-found ${i}
  done
}

# base64 decode that also works with base64url variant (no padding)
b64d() {
  local data=""
  while IFS= read -r line || [ -n "$line" ]; do
    data+="$line"
  done
  echo "${data}==" | base64 --decode
}

# nextcloud
occ() {
  NEXTCLOUD_POD_NAME=$(kubectl get pod -n cosmoknots -l app.kubernetes.io/name=nextcloud -o jsonpath='{.items[0].metadata.name}')
  kubectl exec -n cosmoknots $NEXTCLOUD_POD_NAME -c nextcloud -i -t -- sudo -u '#33' PHP_MEMORY_LIMIT=512M /var/www/html/occ "$@"
}

# yt-dlp
# https://github.com/yt-dlp/yt-dlp
ytd() {
  yt-dlp --cookies-from-browser=firefox \
    --replace-in-metadata "uploader_id" "^@" "" \
    --output "$HOME/Downloads/yt-dlp/%(uploader_id)s/%(extractor)s_%(display_id)s.%(ext)s" \
    --embed-metadata \
    --sponsorblock-mark all \
    "$@"
}

jitter() {
  local secs=$(( ( RANDOM % 60 ) + 1 ))
  echo "sleep for $secs seconds..."
  sleep "$secs"
}
generate_completions
#!/usr/bin/env -S zsh -i

GREY='\033[0;30m'
BG_BLUE='\033[44m'
RESET='\033[0m'

# Declare an associative array
typeset -A PROGRAMS

PROGRAMS=(
    "kubectl"   "kubectl completion zsh"
    "helm"      "helm completion zsh"
    "uv"        "uv generate-shell-completion zsh"
    "uvx"       "uvx --generate-shell-completion zsh"
)

for PROGRAM_NAME GENERATE_CMD in "${(@kv)PROGRAMS}"; do
    echo "Checking for ${PROGRAM_NAME}"
    if command -v "${PROGRAM_NAME}" &> /dev/null; then
        FILENAME="${fpath[1]}/_${PROGRAM_NAME}"
        echo "${BG_BLUE}  FOUND ${PROGRAM_NAME}  ${RESET}"
        echo "Command: ${GREY}${GENERATE_CMD}${RESET}"
        echo "File: ${GREY}${FILENAME}${RESET}"
        eval "${GENERATE_CMD} > ${FILENAME}"
    fi
done
acecat Oh-My-Posh Theme
version = 3

[upgrade]
  source = "cdn"
  interval = "168h"
  auto = false
  notice = false

[palette]
  base = "#1e1e2e"
  text = "#cdd6f4"
  pink = "#f5c2e7"
  red = "#f38ba8"
  yellow = "#f9e2af"
  green = "#a6e3a1"
  teal = "#94e2d5"
  blue = "#89b4fa"

[[blocks]]
  type = "prompt"
  alignment = "left"

  [[blocks.segments]]
    template = "{{ if .WSL }}WSL at {{ end }}{{.Icon}}"
    foreground = "p:text"
    type = "os"
    style = "plain"

  [[blocks.segments]]
    template = " \uf0e7"
    foreground = "p:red"
    type = "root"
    style = "plain"

  [[blocks.segments]]
    template = " {{ if eq .PWD \"~\" }}\uf015{{ else }}\uf07c{{ end }} {{ .Path }}"
    foreground = "p:blue"
    type = "path"
    style = "plain"

    [blocks.segments.properties]
      style = "full"
      folder_format = "<d>%s</d>"
      edge_format = "<b>%s</b>"

  [[blocks.segments]]
    template = " {{ .UpstreamIcon }} {{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \uf044 {{ .Working.String }}{{ end }}{{ if and (.Staging.Changed) (.Working.Changed) }} |{{ end }}{{ if .Staging.Changed }} \uf046 {{ .Staging.String }}{{ end }}"
    foreground = "p:yellow"
    type = "git"
    style = "plain"

    [blocks.segments.properties]
      fetch_upstream_icon = true
      fetch_status = true

[[blocks]]
  type = "prompt"
  alignment = "right"

  [[blocks.segments]]
    template = " <p:red>\uf071 {{ reason .Code }}({{ .Code }})</>"
    type = "status"
    style = "plain"

  [[blocks.segments]]
    template = " \uf252 {{ .FormattedMs }}"
    type = "executiontime"
    style = "plain"

    [blocks.segments.properties]
      style = "round"
      threshold = 3000

  [[blocks.segments]]
    template = "{{ if .SSHSession }} \ueba9 {{ .UserName }}@{{ .HostName }}{{ end }}"
    foreground = "p:yellow"
    type = "session"
    style = "plain"

  [[blocks.segments]]
    template = " \uf017 {{ .CurrentDate | date .Format }}"
    foreground = "p:blue"
    type = "time"
    style = "plain"

    [blocks.segments.properties]
      time_format = "15:04:05"

[[blocks]]
  type = "prompt"
  alignment = "left"
  newline = true

  [[blocks.segments]]
    template = "āÆ "
    foreground = "p:green"
    type = "status"
    style = "plain"
    foreground_templates = ["{{ if gt .Code 0 }}p:red{{ end }}"]

    [blocks.segments.properties]
      always_enabled = true

[[tooltips]]
  template = "\ue81d {{.Context}}{{if .Namespace}} :: {{.Namespace}}{{end}}"
  type = "kubectl"
  style = "plain"
  tips = [ "kubectl" ]

Finishing Touches

To use delta with git, update your ~/.gitconfig with the following:

[interactive]
    diffFilter = delta --color-only
[include]
    path = ~/.local/share/themes/catppuccin.gitconfig
[delta]
    features = catppuccin-mocha
    side-by-side = true
    navigate = true    # use n and N to move between diff sections
    dark = true
[merge]
    conflictstyle = zdiff3
[diff]
    colorMoved = default