# Zsh Config A reproducible, self-configuring Zsh setup managed from a remote git repo. The `zshrc` auto-updates itself and the Starship prompt config on every interactive shell start, and a versioned bootstrap script installs all missing dependencies across distros. Drop `~/.zshrc` in place once and every machine stays in sync automatically. ## Design - **Reproducible** — one `zshrc` drives an identical environment across every machine and distro. - **Self-configuring** — tool integrations are guarded by `command -v`, so the shell works degraded-but-fine when a tool is absent, and lights up automatically once the bootstrap installs it. - **Self-updating** — on each interactive shell start, `zshrc` and `starship.toml` are re-pulled from the repo and applied if changed (downloaded files are validated with `zsh -n` before replacing anything, so a 502 error page or corrupted content can't break the shell). - **Network-resilient** — all remote calls use `--fail` + `--connect-timeout`/`--max-time`, so an unreachable server silently no-ops instead of hanging the shell. ## Files | File | Description | |------|-------------| | [`zshrc`](zshrc) | Main config. Path setup, history options, oh-my-zsh + plugins, eza theme, tool integrations, aliases, and the auto-update logic. Sources `~/.zshrc.local` at the end for per-machine overrides. | | [`zshrc-bootstrap.zsh`](zshrc-bootstrap.zsh) | One-shot setup script run by `zshrc` when the bootstrap version changes. Installs all dependencies across distros and clones oh-my-zsh + custom plugins. | | [`starship.toml`](starship.toml) | Starship prompt config — two-line prompt with directory, git status, command duration, Nerd Font symbols, and an error indicator. Synced to `~/.config/starship.toml` by the auto-update logic. | | [`tmux.conf`](tmux.conf) | Tmux config with GitHub Dark theming, Vim-style pane navigation (`h/j/k/l`), TPM plugin manager, Nerd Font auto-install, and a built-in cheatsheet (`prefix + ?`). Installed to `~/.config/tmux/tmux.conf` on first shell start. | ## Getting Started Point `~/.zshrc` at the remote `zshrc`: ```bash curl -fsSL https://git.jeremymcclure.com/jeremy/scripts/raw/branch/master/zsh/zshrc -o ~/.zshrc && exec zsh ``` On first start, `zshrc` bootstraps missing dependencies (oh-my-zsh, plugins, and all CLI tools below) over the next shell starts. To force a re-bootstrap (e.g., after adding new tool installs to the bootstrap script), the bootstrap version is bumped in `zshrc` and every machine re-runs it automatically — or run manually: ```bash BOOTSTRAP=true exec zsh ``` ## Dependencies All installed automatically by the bootstrap across brew / apt / dnf / pacman / cargo: | Tool | Purpose | |------|---------| | starship | Prompt (configured via `starship.toml`) | | fzf | Fuzzy finder — powers `fzf-tab` completion and `zi` | | eza | `ls` replacement with icons, git status, hyperlinks | | bat | `cat` replacement + colored man pages | | zoxide | Frecency directory jumping (`z`, `zi`) | | git-delta | Pretty `git diff`/`log`/`show` pager | | fastfetch | System info on shell start | | lazydocker | TUI for Docker | | rsync / tmux / git | Core utilities | Debian/Ubuntu renames handled: `batcat`→`bat`, `fdfind`→`fd` (symlinked into `~/.local/bin`). ## Oh-My-Zsh Plugins `git`, `sudo`, `extract`, `eza`, `history`, `kitty`, `docker`, `docker-compose`, `archlinux`, `encode64`, `universalarchive`, `zsh-autosuggestions`, `fast-syntax-highlighting`, `fzf`, `fzf-tab`, `systemd`, `vscode`, `rsync`, `starship`. ## Tool Integrations Each is enabled only when the binary is present (`command -v`): - **zoxide** — `z ` jumps to frecency-ranked dirs; `zi` opens the fzf picker. `cd` still works. - **bat** — `alias cat='bat'`, `BAT_THEME=Monokai Extended`, and `MANPAGER` set so `man` pages are colored and paginated by bat. - **delta** — `GIT_PAGER=delta` so `git diff`/`log`/`show` render side-by-side with syntax highlighting. (Not aliased to `diff` — delta is a pager reading diff input on stdin, not a `diff a b` replacement.) ## History & Shell Options `SHARE_HISTORY`, `HIST_IGNORE_DUPS`, `HIST_IGNORE_ALL_DUPS`, `HIST_REDUCE_BLANKS`, `HIST_FCNTL_LOCK`, `HIST_VERIFY`, `EXTENDED_HISTORY`, `AUTO_CD`, `AUTO_LIST`, `INTERACTIVE_COMMENTS`, `AUTO_PUSHD`, `PUSHD_IGNORE_DUPS`, `PUSHD_SILENT`. `AUTO_PUSHD` maintains an automatic directory stack, so `cd -` and `dirs` let you navigate recent locations without `pushd`/`popd` muscle memory. ## Aliases | Alias | Action | |-------|--------| | `c` | `clear` | | `q` | `exit` | | `open-ports` | `ss -tulpn \| grep LISTEN` | | `nbstat` | Netbird peer status as a TSV table | | `yeet` | `yay -Rcs` (remove + deps + config on Arch) | ## Keybindings | Shortcut | Action | |----------|--------| | `Ctrl+R` | fzf history search (via `fzf` plugin) | | `Ctrl+T` | fzf file finder | | `Alt+C` | fzf cd | | `Tab` | `fzf-tab` completion menu | | `Esc` twice | Toggle `sudo` prefix (via `sudo` plugin) | ## Eza Hyperlinks — Implementation Note `zshrc` does **not** set the oh-my-zsh `eza` plugin's `hyperlink` zstyle (the plugin's bare `--hyperlink` causes issues). Instead, after oh-my-zsh loads, the aliases are rewritten to append the correct hyperlink flag for the installed eza version: - **Newer eza** (help shows `--hyperlink []`): the oh-my-zsh plugin's bare `--hyperlink` is treated by clap as taking the *next token* as its optional value, so `la /` fails with `invalid value '/'`. We append the glued `--hyperlink=always` form, which can't eat a following path argument. - **Older eza** (e.g. Debian's, where `--hyperlink` is a pure boolean): `--hyperlink=always` is rejected with `Flag --hyperlink cannot take a value`. We detect this via `eza --help` and fall back to the bare `--hyperlink`, which is safe here because boolean flags don't consume the next token (the path-eating bug doesn't apply). Detection runs once at shell start via `eza --help | grep ''`; the right form is applied to every eza alias. Hyperlinks stay on and paths keep working across eza versions. ## Auto-Update Behavior On every interactive shell start: 1. **zshrc** — re-downloaded, validated with `zsh -n`, and applied via `exec zsh` only if it differs from `~/.zshrc`. 2. **starship.toml** — re-downloaded and moved to `~/.config/starship.toml` if changed (applied live on the next prompt render; no shell reload needed). 3. **tmux.conf** — downloaded once on first shell start if `~/.config/tmux/tmux.conf` and `~/.config/byobu/.tmux.conf` are both absent. 4. **bootstrap** — runs (`zshrc-bootstrap.zsh`) when `ZSHRC_BOOTSTRAP_VERSION` in `zshrc` doesn't match `~/.config/zsh/.bootstrapped`. All downloads use `--fail` so a 502/HTML error page is never written over a working config, and `--connect-timeout`/`--max-time` so an unreachable server never hangs startup. ## Per-Machine Overrides `~/.zshrc.local` is sourced at the very end of `zshrc` (created empty if missing). Put machine-specific aliases, env vars, or PATH additions there — they survive repo updates since `zshrc` doesn't manage that file. ## Environment Variables | Variable | Default | Purpose | |----------|---------|---------| | `ZSHRC_GIT` | `.../scripts/raw/branch/master/zsh/` | Base URL for all remote config files | | `ZSHRC_BOOTSTRAP_VERSION` | `4` | Bump to force a re-bootstrap on all machines | | `FFENABLED` | (unset → enabled) | Set to `false` to disable the fastfetch system info on shell start | | `BAT_THEME` | `Monokai Extended` | Override before the bat block to use a different bat theme | | `GIT_PAGER` | `delta` (when installed) | Override to use a different git pager | ## Helper Functions ```bash update_zshrc # Manually re-pull and reload the zshrc fix_btopbg # Disable btop theme_background (workaround for transparency) install_opencode # Install the opencode CLI BOOTSTRAP=true exec zsh # Force a re-bootstrap ```