Newer eza (clap) treats --hyperlink as taking an optional value, so the oh-my-zsh plugin's bare --hyperlink eats the next path arg (la / -> invalid value '/'). The previous fix glued --hyperlink=always to avoid that. But Debian ships an older eza where --hyperlink is a pure boolean that rejects a value, so --hyperlink=always errors with 'Flag --hyperlink cannot take a value'. Detect the installed eza's behavior via 'eza --help | grep <WHEN>': - newer eza: use --hyperlink=always (glued, avoids path-eating) - older eza: use bare --hyperlink (boolean, doesn't eat tokens so the original bug doesn't apply) Apply the chosen form to every eza alias. Both paths keep hyperlinks on and paths working.
132 lines
7.8 KiB
Markdown
132 lines
7.8 KiB
Markdown
# 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 <substring>` 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 -<TAB>` 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 [<WHEN>]`): 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 '<WHEN>'`; 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
|
|
``` |