Terminal & Shell Setup¶
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.
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