Solarized Dark terminal showing eza, bat, git-delta, fzf

Terminal — Getting Started & Cheatsheet

Solarized Dark, end-to-end · eza · bat · git-delta · difftastic · glow · vivid · procs · lnav · xh · fzf · fzf-tab · zsh-autosuggestions · zsh-syntax-highlighting
view full screenshot

Getting started / what's installed

Brew packages (recently added)

ezals replacement with icons + git status
batsyntax-highlighted cat / man pager backend
git-deltagit diff/log/blame pager
difftasticsyntactic diff for ad-hoc compares (non-git)
glowrender markdown to ANSI (powers md alias)
vividgenerates LS_COLORS palettes
procsmodern ps replacement (Rust)
tailspinlive-log highlighter (tspin); Solarized via ~/.config/tailspin/theme.toml
lnavTUI log navigator; Solarized via built-in theme (see lnav section)
btopmodern top replacement; Solarized via ~/.config/btop/btop.conf
xhmodern HTTP client (HTTPie-compatible CLI); Solarized via ~/.config/xh/config.json
zsh-autosuggestionsghost-text completion from history
zsh-syntax-highlightinglive command-line highlighting
fzffuzzy finder + Ctrl-R / Ctrl-T bindings
fzf-tabreplaces zsh's Tab menu with an fzf picker

House rules (per CLAUDE.md)

What aliases you get

catbat --paging=never
lessfunction → bat wrapper (file = full decoration; pipe = --plain)
mdglow --style ~/.config/glow/glamour.json
mdpmd -p (paged via real less)
lseza --group-directories-first --icons
lleza -lh --git --icons --group-directories-first
lall -a
vim / vimdiffnvim (guarded on command -v nvim)
vicommand vim (legacy minimal vim, suppresses recursive alias)
psprocs (Solarized; PID asc; ps-like columns)
pshprocs --load-config ~/.config/procs/procs-heavy.toml (CPU desc, trimmed)
topbtop (modern colorful TUI, Solarized; command top for BSD top)

BSD \ls still works (escape skips alias) and uses OMZ's default LSCOLORS. Use command less to reach real less for less +F, -R, etc. command ps / \ps / /bin/ps reach legacy ps.

eza ls replacement

Most-used flags

ezasimple list (icons via alias)
eza -llong form
eza -lhlong + human sizes
eza -lashow hidden
eza --gitadd a git-status column
eza --tree -L 2tree view, depth 2
eza -s modifiedsort by mtime
eza -s sizesort by size
eza --group-directories-firstdirs on top (default in alias)

Recipes

ll -s modified -rmost recently changed first
ll --git-ignorehide gitignored files
eza -laT --git-ignore -L 3tree, hidden, no gitignored, 3 deep
eza -l --time-style=long-isoISO timestamps

Colors come from LS_COLORS (set by vivid). Icons need a Nerd Font in your terminal.

procs modern ps

Most-used flags

procsall your processes, Solarized columns, sort by PID
procs zshregex search across PID/User/Command (replaces ps | grep)
procs --treeparent/child tree view
procs --watchrefresh every 1s; --watch-interval N for custom
procs --sortd UsageCpusort by CPU descending (asc = --sorta)
procs --insert VmRssadd a column on the fly (kinds: procs --list)

Aliases & configs

psprocs (default Solarized view)
pshprocs --load-config ~/.config/procs/procs-heavy.toml (CPU desc, trimmed)
~/.config/procs/procs.tomldefault config (in-repo, symlinked)
~/.config/procs/procs-heavy.tomltrimmed columns + CPU-desc; loaded by psh

Both TOMLs duplicate their [style.*] blocks; procs --load-config replaces the whole config (no inheritance). Edit both when tweaking colors.

macOS caveat

procs on macOS only shows your own processes — Apple gates cross-user visibility behind elevated privileges. To see system daemons (the _appstore, _audiomxd, etc. that ps -ax shows), fall through to legacy: \ps -ax or command ps -ax.

Pipes strip color (color_mode = "Auto"). Prefer procs <pat> over ps | grep <pat> — same result, colors preserved.

Most-used invocations

lnav file.logopen one file (auto-tails new lines)
lnav dir/open every log file in a directory; merged by timestamp
cmd | lnavread from stdin (no positional arg)
lnav -n file.logheadless / no UI (useful for format debugging)

Files we ship

~/.config/lnav/configs/installed/solarized-dark.jsonactivates lnav's built-in Solarized Dark theme
~/.config/lnav/formats/installed/inngest.jsonJSON format for inngest-cli dev stdout
~/.config/lnav/config.jsonlnav's runtime mutable config (not in repo)

Add new formats by dropping a JSON file in formats/installed/ — the installed/ dir is symlinked from the repo, so no bootstrap.sh re-run is needed. (lnav owns the rest of ~/.config/lnav/.) Theme is lnav's built-in (palette matches bat / delta / procs / btop); we don't redefine slots.

Inside the TUI

qquit
e / Enext / prev error
w / Wnext / prev warning
/pat / nsearch / next match
:command prompt (e.g. :filter-in, :goto)
;SQL prompt — query log lines as a table (e.g. SELECT * FROM inngest_dev WHERE level = 'error')
t / itime histogram / global histogram view
TABswitch between log view and bottom prompt

Bottom status bar shows the matched format name (e.g. inngest_dev) when an installed format matches the file.

bat cat with syntax highlighting

Daily use

cat file.rbaliased to bat --paging=never
bat file.rbpaged, with line numbers + git gutter
bat -p fileplain (no decoration)
bat -A fileshow non-printables (whitespace, line endings)
bat -r 10:50 filerange lines 10–50
bat -l json dataforce language
bat --diff fileonly show modified hunks
man <cmd>uses bat -l man via $MANPAGER

Theme & introspection

bat --list-themesall themes
bat --list-languagessupported languages
bat --theme="Solarized (dark)"force theme
$BAT_THEMEenv override

$MANPAGER is set so man stays Solarized: sh -c 'col -bx | bat -l man -p --paging=always'. $MANROFFOPT=-c keeps ANSI sequences intact.

Inside the pager

Space / bpage down / up
/pat / nsearch / next match
g / Gtop / bottom
qquit

bat shells out to less by default — these are less keys.

less wrapper bat for files, plain for pipes

Why a function, not an alias

less is a zsh function (defined next to the cat alias in .zshrc) that delegates to bat. File arguments get bat's full decoration (line numbers, git gutter); piped input falls back to bat --plain so cmd | less doesn't get bat's STDIN header and stays clean.

$PAGER is not set to bat globally — git/delta and other tools manage their own pagers. The wrapper only shadows interactive less use.

Usage

less file.rbbat with full decoration (paged)
cat file | lessbat --plain (no header)
command less +F logreal less follow-mode
command less -Rreal less raw control chars

Inside the pager, all less keys work (Space/b, /pat, g/G, q) — bat shells out to less.

git-delta git diff pager

Where it kicks in

Wired through git config — anything that paginates a diff uses delta:

git diffside-by-side or unified, syntax-highlighted
git log -pcommit-by-commit diff
git show <rev>single commit
git blamestyled blame
git add -pinteractive — uses delta as the diff filter

Inside delta's pager

n / Nnext / prev file (navigate=true)
/ / ?search
Space / bpage down / up
qquit

Built on less, so less keys all work.

Useful flags

git diff --side-by-sidetwo-column layout
delta --lightforce light theme one-shot
delta --no-gitconfig --diff-highlightminimal preview
git -c core.pager=cat diffbypass delta one-shot

difftastic non-git diff

Where it kicks in

Aliased over diff for ad-hoc file compares outside git. Git diffs still flow through delta (see above) — the two cover different surfaces.

diff a bsyntactic, language-aware diff between two files
diff a/ b/recursive directory diff
diff old.json new.jsontree-sitter parses each side; structural moves are recognized

Bypass to legacy diff

command diff a bskip the alias (zsh built-in)
\diff a bsame; backslash quotes the alias name
/usr/bin/diff a babsolute path bypasses $PATH

Non-interactive shells (scripts, Make, CI) never see the alias — zsh aliases don't propagate without -i.

Why no theme pin

Difftastic uses ANSI 16-color directly; Ghostty's terminal palette is already Solarized Dark, so it inherits on-palette colors with no extra config. The default --background dark matches; nothing to wire.

Don't introduce delta, diff-so-fancy, or another diff renderer for non-git — they're line-based, not syntactic, and would duplicate what delta already does for git.

glow / md markdown renderer

The md alias

md renders markdown to ANSI via glow with a pinned Solarized style:

alias md='glow --style $HOME/.config/glow/glamour.json'

bat / less / cat still show the source with syntax highlighting; md shows the rendered output (headings, lists, code-block themes).

Why --style, not glow.yml

glow on macOS reads its yaml from ~/Library/Preferences/glow/, not ~/.config/glow/. The alias passes --style directly so the Solarized JSON in this repo (.config/glow/glamour.json) is used regardless.

Fenced code blocks inside markdown use chroma's solarized-dark theme to stay on-palette.

Usage

md README.mdrender to terminal
md -p README.mdpaged (uses $PAGER / less)
mdp README.mdsame as md -p (dedicated alias)
md -w 100 README.mdforce width 100
cat foo.md | md -render from stdin
command glow ...bypass alias (no --style)

Don't swap to mdcat / frogmouth without an explicit ask — mdcat was archived upstream 2025-01-10.

tailspin / tspin live-log highlighter

Daily use

tspin file.logopen file (paged via less)
tspin -f file.logfollow (live tail with highlights)
cmd | tspin -ppipe stdin, print to stdout (no pager)
tspin -e 'kubectl logs -f pod'run command, view paged output

No tail alias and no t shortcut — tail / tail -n stay vanilla. tspin's CLI isn't a tail superset (no -n), so wrapping tail would break common uses.

Theme — Solarized via theme.toml

tspin reads ~/.config/tailspin/theme.toml. It accepts ANSI color names only (red, blue, bright_red, …); Ghostty's Solarized Dark palette resolves them to hex via the canonical Solarized terminal mapping:

redred #dc322f
bright_redorange #cb4b16
bright_magentaviolet #6c71c4
bright_greenbase01 #586e75
bright_cyanbase1 #93a1a1

Severity (error / warn / info / debug) is shipped as [[keywords]] blocks — tspin has no built-in groups for them.

What gets highlighted

Schema: github.com/bensadeh/tailspin/blob/main/src/theme/mod.rs. Override anything with extra [[keywords]] or block-level entries.

xh modern HTTP

Most-used invocations

xh GET httpbin.org/getbasic GET; pretty-prints JSON in Solarized colors
xh POST httpbin.org/post name=aliceJSON body via key=value shorthand (no --data)
xh -a user:pass api.example.combasic auth (HTTPie-compatible flag)
xh --download urlsave body to a file (filename inferred)
xhs api.github.com/zenHTTPS-default companion binary (no https:// needed)
xh --style=monokai GET …override the default Solarized theme per-invocation

Why a config file (and what's in it)

Solarized is pinned via ~/.config/xh/config.json:

{"default_options": ["--style=solarized"]}

xh --style accepts auto, solarized, monokai, fruity. xh renders through syntect — the same library family as bat — so highlighting matches the rest of the Solarized Dark setup.

No .zshrc alias here. Aliases in this repo are reserved for swapping commands; default flags belong in config files.

Coexistence with curl

curl is unchanged. Scripts, CI, and any non-interactive use keep calling curl verbatim. xh/xhs are the interactive surface only.

Don't alias curl to xh, and don't introduce an http/https alias either — the binary's own name is the only entry point.

hyperfine command benchmarking

Most-used invocations

CommandWhat it does
hyperfine 'cmd'10 runs, no warmup, summary with mean/stddev
hyperfine --warmup 3 'cmd'discard 3 warmup runs first (cache, JIT)
hyperfine 'a' 'b'A/B compare; prints "X is N× faster than Y"
hyperfine -N 'cmd'skip shell wrapper; measure binary directly
hyperfine --export-markdown out.md 'cmd'share results in markdown

When to reach for it vs time

time (zsh builtin / /usr/bin/time) is the right tool for one-shot wall-clock measurements — scripts, CI, "did this finish quickly?". Reach for hyperfine when you want warmups, multiple runs, variance characterization, or A/B comparison.

Deliberately not aliased to time — semantics differ. See CLAUDE.md for the catalog-rejection rationale.

Caveats

First run includes filesystem cold-cache effects. Use --warmup N or --prepare 'sync' to control. macOS purge needs sudo if you want to flush page cache between runs.

modern-reminder discoverability nudge

What it does

One-line nudge after running a default tool whose modern alternative is installed and deliberately left unaliased. Fires at most once per zsh process, per command name. A fresh tmux pane resets the seen set.

DefaultModern
tailtspin
greprg (ripgrep)
curlxh (HTTPie-compatible)

Toggle

export MODERN_REMINDER=1 in ~/.zshrc turns it on (set there by default). Comment that line — or unset MODERN_REMINDER in a single shell — to silence.

Hooks register only in interactive shells, so scripts and CI never see them.

Where it lives

Implementation: _modern_reminder_preexec + _modern_reminder_precmd in ~/.zshrc; tests in scripts/test-modern-reminder.zsh (which holds a synced copy of the function bodies — keep both in sync).

vivid & LS_COLORS

What & how

vivid generates a LS_COLORS string from a named palette. .zshrc exports it on startup:

command -v vivid >/dev/null 2>&1 && \
  export LS_COLORS="$(vivid generate solarized-dark)"

Both eza and GNU ls read $LS_COLORS. BSD ls uses $LSCOLORS (different format) — left at OMZ default.

Tweak / preview

vivid themeslist available palettes
vivid generate molokaitry another palette one-shot
echo $LS_COLORS | tr ':' '\n'inspect current rules
vivid -m 8-bit generate solarized-dark256-color mode (24-bit is default)

Solarized-dark is the pinned palette — switching is OK to try, but persist anything else only after asking.

fzf fuzzy finder

Shell key bindings

Ctrl-Rfuzzy history search
Ctrl-Tfile picker → inserts paths at the cursor
Alt-CUNBOUND — Alt is reserved for Polish diacritics

Tab-complete works through fzf for kill **<Tab>, cd **<Tab>, ssh **<Tab>, etc.

Inside the prompt

Ctrl-J / Ctrl-Knext / prev item
Tab / Shift-Tabmulti-select
Enteraccept
Esc / Ctrl-Ccancel
'fooexact match (single-quote prefix)
!foonegate
^foo / foo$prefix / suffix anchor
foo | barOR

Common one-liners

vim $(fzf)pick a file, open in vim
git checkout $(git branch | fzf)branch picker
fd | fzf --preview 'bat --color=always {}'live preview
history | fzfmanual history search

FZF colors are pinned to Solarized via $FZF_DEFAULT_OPTS in .zshrc.

fzf-tab Tab completion picker

What it does

Replaces zsh's default Tab completion menu with an fzf picker — fuzzy filter as you type, arrow-key navigation, and per-command previews. Works for every command (cd, git, kill, ssh, brew, …).

For z with zoxide-ranked results, use zi <query> — fzf-tab won't show zoxide entries because zoxide init zsh doesn't register a _z completion function.

Key bindings (inside the picker)

Tabaccept selected completion
< / >switch between completion groups (e.g. [heads][tags] for git checkout)
Ctrl-Spacemulti-select
/continuous completion (useful for deep paths)
Esccancel

Examples

cd <Tab>directory picker with eza preview pane
git checkout <Tab>branches + tags grouped with headers
kill <Tab>process picker
brew install <Tab>formula picker

Picker colors inherit $FZF_DEFAULT_OPTS via use-fzf-default-opts yes.

Commands

disable-fzf-tabfall back to compsys for this shell
enable-fzf-tabre-enable
toggle-fzf-tabflip between the two

zsh-autosuggestions ghost text from history

Accept the suggestion

(right arrow)accept entire suggestion (end-of-line)
Ctrl-Esame — move to end of line (accepts)
Ctrl-F / M-fforward by char/word — Alt is unbound here
Esc then Enterdiscard suggestion, run only what you typed

Notes

zsh-syntax-highlighting live command line

What you'll see

It's the last sourced plugin — that's a hard requirement of the project, not a style choice. Sourcing it earlier breaks coloring of subsequent plugins' bindings.

Tweak (rarely needed)

# In ~/.zshrc.local (machine-local, untracked)
typeset -A ZSH_HIGHLIGHT_STYLES
ZSH_HIGHLIGHT_STYLES[command]='fg=#859900,bold'  # green
ZSH_HIGHLIGHT_STYLES[unknown-token]='fg=#dc322f'     # red

Don't change the global Solarized palette — palette pins are intentional.

Bootstrap a new machine

Full new-machine setup is in README.md → "Setup (new machine)". The steps below are the terminal-relevant subset.

# 1) Brew packages
brew bundle --file=$PROJECTS_HOME/dotfiles/Brewfile

# 2) Symlinks (idempotent)
$PROJECTS_HOME/dotfiles/bootstrap.sh

# 3) Wire delta into git (one-time, global)
git config --global core.pager delta
git config --global interactive.diffFilter "delta --color-only"
git config --global delta.navigate true
git config --global delta.line-numbers true
git config --global delta.syntax-theme "Solarized (dark)"

# 4) Verify
brew bundle check --file=$PROJECTS_HOME/dotfiles/Brewfile --verbose
echo $LS_COLORS | head -c 80      # should not be empty
git log -p | head                 # should look styled

Plugin source order in .zshrc (do not reorder)

  1. fzf completion.zsh + key-bindings.zsh — binds ^I
  2. bindkey -r '^[c' — remove fzf's Alt-C binding (Polish diacritics)
  3. zoxide init zsh
  4. fzf-tab.zsh — needs fzf's ^I already bound; must be before any plugin that wraps widgets
  5. zsh-autosuggestions.zsh
  6. zsh-syntax-highlighting.zshmust be last