>_EXECUTIVE SUMMARY
zsh-expand rewrites the spacebar into a live alias expander. Every press of Space runs a ZLE widget that walks the current command line, resolves the command position through arbitrarily deep prefix chains (sudo, env, nice, nsenter, strace, ltrace, nohup, rlwrap, numactl, chrt, ionice, flock, unshare, setpriv, setarch, ...), and dispatches to one of:
regular alias expand, global alias expand, suffix alias expand (alias -s), misspelling correction, glob / parameter / history expansion via zle expand-word, or fall-through. Total surface: 2,753 zsh lines across 4 source files, pinned by 11,683 @test blocks across 78 zunit files. Zero external commands in the hot path — the entire expansion is pure parameter expansion, associative lookup, and shell-builtin parsing. Hot-path latency: ~36 µs per regular alias expand.
~ARCHITECTURE
Four-file load order. The plugin entry point sources the parser first (pure functions, no side effects), then the API (state container helpers), then the lib (widget bodies + dictionary). Final block defines ZLE widgets, binds Space + Ctrl-Space + Esc-Ctrl-E, and adds completions/ to fpath.
| File | Lines | Role |
|---|---|---|
zsh-expand.plugin.zsh |
443 | Plugin entry point. Sources the three siblings, defines the 292 built-in correction entries, declares ZLE widgets (zpwrExpandSupernaturalSpace, zpwrExpandTerminateSpace, zpwrExpandGlobalAliases, zpwrExpandDebugWidget), binds keys, registers the _zpwrExpandStats completion via compdef. |
zpwrExpandParser.zsh |
929 | Prefix-chain parser. Walks the current buffer left-to-right, consumes nocorrect / builtin / command / exec / eval / noglob / coproc shell keywords first, then iterates external prefix commands (sudo, doas, env, nice, nohup, rlwrap, timeout, strace, ltrace, ionice, caffeinate, setsid, chrt, taskset, watch, flock, chroot, runuser, unshare, cpulimit, su, stdbuf, ...) with their full flag tables. Variable assignments (X=1) are skipped at any position. |
zpwrExpandLib.zsh |
1,179 | Widget bodies. Implements the expansion state machine: alias resolve → global resolve → correction lookup → native expand. Holds the O(1) reverse-lookup dictionary build (ZPWR_EXPAND_CORRECT_REVERSE). Suffix alias handling, self-referential \backslash escape, blacklist enforcement, autopair detection / delegation, history injection, preview ghost text, stats append. |
zpwrExpandApi.zsh |
202 | State-container helpers and config init. Exports ZPWR_VARS association keys consumed by the parser/lib, sets default values for the ZPWR_EXPAND_* / ZPWR_CORRECT_* family, declares the public-callable shape (caller / enter detection, multiword tail extraction). |
| Total source | 2,753 | 4 files · pure zsh · zero forks in hot path |
#TEST COVERAGE
78 zunit test files (tests/t-*.zsh) totalling 11,683 @test blocks. Coverage is partitioned by area — each file pins one class of behavior with exhaustive edge cases.
| Area | Representative Files | Pins |
|---|---|---|
| Alias expansion | t-alias-position.zsh, t-alias-escape-edge.zsh, t-expand-alias-edge.zsh, t-expand-combo.zsh, t-expand-more.zsh, t-expand-unit.zsh, t-expand-utility-edge.zsh, t-expand-parse-edge.zsh |
First-position vs subcommand-position expand; self-referential alias \backslash escape; combined prefix + alias chains; deep-stack regression. |
| Spelling correction | t-correct-context.zsh, t-correct-dict-full.zsh, t-correct-exhaustive.zsh, t-correct-guards.zsh, t-correct-multi-ctx.zsh, t-correct-user-extend.zsh, t-correct-word-edge.zsh |
All 292 built-in entries round-trip; user-extension hook; correct-then-expand chain; per-context guards (don't correct real commands). |
| Prefix-chain blacklist | t-blacklist-firstpos-alias.zsh, t-blacklist-subcommand-suffix.zsh |
ZPWR_EXPAND_BLACKLIST wins in command position AND after every supported prefix; suffix-alias exclusion respected. |
| Config flag matrix | t-config-flags.zsh, t-api-caller-and-enter.zsh, t-api-multiword-tail.zsh |
Every ZPWR_EXPAND_* toggle pinned on + off; caller-context API behaves the same on Enter as on Space; multi-word tail extraction. |
| Debug widget & UI | t-box-backspace-and-color.zsh, t-box-double-dash.zsh, t-box-fuzz.zsh |
Esc-Ctrl-E debug-overlay rendering: ANSI escapes don't poison ${#string} math; backspace doesn't corrupt the line; fuzz-input doesn't crash the widget. |
Runner: zunit. CI matrix (.github/workflows/ci.yml) runs the full 11,683 on every push.
/INTEGRATION
Zinit (recommended)
zinit ice lucid nocompilezinit load MenkeTechnologies/zsh-expand
The plugin's 0= header follows the Zsh Plugin Standard; nocompile keeps the source path stable for the ${0:A:h} resolution of sibling files.
Oh My Zsh
git clone into $ZSH_CUSTOM/plugins/zsh-expand, then plugins+=(zsh-expand) in .zshrc. No init hook required — the file is sourced top-to-bottom and the ZLE widgets register before the prompt fires.
ZLE widgets installed
Four widgets registered via zle -N: zpwrExpandSupernaturalSpace (bound to Space), zpwrExpandTerminateSpace (bound to Enter when ZPWR_EXPAND_PRE_EXEC_NATIVE=true), zpwrExpandGlobalAliases (callable from user widgets), zpwrExpandDebugWidget (bound to Esc-Ctrl-E).
Completion registration
fpath+=(${0:A:h}/completions) adds the one shipped completion file (completions/_zpwrExpandStats) for the zpwrExpandStats command, then compdef _zpwrExpandStats zpwrExpandStats registers it when compsys is active.
Autopair coexistence
If zsh-autopair is detected, the supernatural-space widget delegates the trailing space insertion to autopair's own autopair-insert rather than emitting a raw space — bracket/quote auto-pairing keeps working after expansion.
Preview hook
When ZPWR_EXPAND_PREVIEW=true, the plugin installs a chained zle-line-pre-redraw hook (preserves any pre-existing user hook), rendering ghost-text of what the next Space would expand to. No polling — fires on the existing ZLE redraw cadence.
!DESIGN DECISIONS
O(1) reverse lookup, not Levenshtein
The 292 entries declare correct → list of misspellings. On load, zpwrExpandRebuildCorrectReverse inverts to misspelling → correct, so correction is one associative-array probe per word, not an edit-distance scan against the dictionary. Userland additions plug into the same rebuild path.
Parse the prefix chain, don't peel one prefix
Naive plugins handle sudo gco by stripping sudo and re-running the test. zsh-expand instead walks an open-ended chain (sudo -kE -u root env -0iv -C /tmp nice -n 10 nohup gco) honoring every flag table from the README. The cost: a 929-line parser. The gain: arbitrarily deep prefix combos work without per-case tuning.
Flag tables hand-curated per command
Each of the 62 supported prefixes lists its combo flags (consume next char) AND its flag-with-arg flags (consume next word). Mixing these is what lets strace -cf -s 256 gco and su -l root gco both work. The flag tables live in zpwrExpandParser.zsh and are pinned by t-expand-combo.zsh regression tests.
Self-referential alias = backslash escape
alias git=hub would loop forever under naive recursion. zsh-expand detects when the head of the expansion equals the original command and prepends \\ to suppress the second-round lookup — the same trick zsh's own _expand_alias uses internally. Pinned by t-alias-escape-edge.zsh.
Blacklist over whitelist
ZPWR_EXPAND_BLACKLIST=(g gco) ships empty by default. Every alias expands unless explicitly excluded — the inverse of opt-in expansion plugins. Lowers config burden: users add the 1–2 aliases they want quiet, not the 100s they want loud.
Zero forks in the hot path
The widget body uses only parameter expansion (${var//pattern/repl}), associative-array indexing ($aliases[word], $galiases[word]), and built-in ZLE state. No sed, no awk, no grep, no $(...) in the expansion path — each fork on macOS is ~1 ms, more than the entire ~36 µs budget.
$POSITION
Quantitative position against the established alias-expansion plugin set. Numbers for siblings come from each project's published README/source as of writing; zsh-expand's figures are derived in-tree by wc -l / grep -c.
| Plugin | Tests | Prefix cmds parsed | Correction dict | Suffix-alias expand | Preview ghost |
|---|---|---|---|---|---|
| zsh-expand | 11,683 | 62 | 292 entries + user-extend | yes | yes |
| globalias (OMZ) | 0 | 0 | none | no | no |
| zsh-abbr | ~100s | 0 | none | no | partial (cursor-time) |
| zsh-abbrev-alias | ~0 | 0 | none | no | no |
| zsh-you-should-use | ~dozens | 0 (post-exec only) | none | n/a | n/a |
Sibling plugins handle the alias-in-command-position case only. zsh-expand is the only one that parses arbitrarily-deep prefix chains AND ships a misspelling-correction dictionary AND ships a suffix-alias hook AND ships preview ghost text — in a single ZLE widget with sub-millisecond latency.
@FOOTPRINT
No daemons. No timers. No state outside zsh.
- Disk:
~/.oh-my-zsh/custom/plugins/zsh-expand(or zinit cache) — one repo clone, no install hook. - Memory: 2 associative arrays (
ZPWR_EXPAND_CORRECT_WORDS,ZPWR_EXPAND_CORRECT_REVERSE) · one global association (ZPWR_VARS) · 4 widget closures. - Startup cost: source + dictionary build + reverse-table build, one-shot, no compile step.
- Runtime cost: 1 widget per Space keystroke · zero external processes · ~36 µs typical.
- Stats file: optional, opt-in via
ZPWR_EXPAND_STATS_FILE— the only on-disk side effect.