>_ZSH-EXPAND
Intercepts your spacebar and expands everything in its path. Regular aliases, global aliases, suffix aliases, misspellings, globs, history, parameters. No pipes. No external commands. Pure zsh. Sub-millisecond. 11,688 tests.
Install
# Zinit (recommended)
zinit ice lucid nocompile
zinit load MenkeTechnologies/zsh-expand
# Oh My Zsh
git clone https://github.com/MenkeTechnologies/zsh-expand \
"$HOME/.oh-my-zsh/custom/plugins/zsh-expand"
# then: plugins+=(zsh-expand)
# Manual
git clone https://github.com/MenkeTechnologies/zsh-expand
source zsh-expand/zsh-expand.plugin.zsh
Neural expansion core
| Alias expansion | regular aliases in command position and after sudo/env/builtin/command/exec/eval/noglob/nocorrect/nice/nohup/rlwrap/time — with full flag support |
| Global alias | global aliases expanded anywhere on the command line |
| Spelling correction | 292 built-in corrections, user-extensible via associative array |
| Native expansion | globs, $params, $(cmd), =(...), !history |
| Tabstop snippets | aliases with $ZPWR_TABSTOP placeholders — cursor jumps to placeholder |
| Self-ref escape | alias git="hub" expands to \hub — no infinite recursion |
| Correct-then-expand | typo correction chains into alias expansion in one keypress |
| Quote-aware expansion | optional expansion inside "double" / 'single' quoted args |
| Suffix alias | file.txt<space> → vim file.txt via alias -s |
| Autopair integration | delegates space insertion to zsh-autopair when present |
| History injection | optionally writes the fully-expanded form into history |
| Debug widget | Ctrl+Opt+E (Esc-Ctrl-E) shows parser state — prefix chain, command position, expansion action — without modifying the line |
| Expansion preview | ghost text shows pending expansion before space is pressed |
| Expansion stats | zpwrExpandStats renders a cyberpunk dashboard with bar charts |
Examples
gco<space> => git checkout sudo gco<space> => sudo git checkout teh<space> => the su -l root gco<space> => su -l root git checkout stdbuf -oL gco<space> => stdbuf -oL git checkout strace -e trace=network gco<space> => ...git checkout file.txt<space> => vim file.txt (suffix alias)
Configuration matrix
# -- core -- export ZPWR_EXPAND=true # master switch; false disables the widget export ZPWR_EXPAND_SECOND_POSITION=true # alias expansion after sudo/env/... export ZPWR_EXPAND_NATIVE=true # expand globs, history, $params # -- correction -- export ZPWR_CORRECT=true # spelling correction export ZPWR_CORRECT_EXPAND=true # expand aliases after correction # -- quotes -- export ZPWR_EXPAND_QUOTE_DOUBLE=true # expand inside "double quotes" export ZPWR_EXPAND_QUOTE_SINGLE=false # expand inside 'single quotes' # -- history -- export ZPWR_EXPAND_TO_HISTORY=false # inject expanded form into history export ZPWR_EXPAND_PRE_EXEC_NATIVE=true # also expand globs on accept-line # -- suffix / preview / blacklist -- export ZPWR_EXPAND_SUFFIX=true # expand suffix aliases (alias -s) export ZPWR_EXPAND_PREVIEW=false # ghost text of pending expansion export ZPWR_EXPAND_BLACKLIST=(g gco) # aliases to never expand # -- stats -- export ZPWR_EXPAND_STATS_FILE=~/.cache/zpwr-expand-stats.dat export ZPWR_EXPAND_STATS_TOP=20 # default top-N in zpwrExpandStats
Key bindings
Space | Supernatural expand + insert space |
Ctrl+Space | Insert literal space (bypass) |
Ctrl+Opt+E | Debug widget — show parser state without expanding |
Expansion rules
Where each expansion class fires — and where it deliberately does not.
| Alias in first word | expanded |
Alias after sudo/env/builtin/… | expanded; prefix matching is case-insensitive (SUDO, Sudo, sUdO all work) |
| Word is a real command/function | not corrected — valid commands are left alone |
| Global alias anywhere on line | expanded |
| Misspelling anywhere on line | corrected |
Globs, $params, !history | expanded (when ZPWR_EXPAND_NATIVE=true) |
| Cursor directly after word | expand |
| One space after word (menuselect) | expand |
| Two spaces after word | bypass |
Bypass protocols
Two ways to keep an alias literal.
Ctrl+Space— insert a literal space, no expansion (one-off).- Blacklist — permanently exclude aliases:
export ZPWR_EXPAND_BLACKLIST=(g gco)
The blacklist wins in command position and after every supported prefix. It ships empty, so every alias expands until you explicitly quiet one.
Supported prefix commands
62 external prefix commands are parsed with their own hand-curated flag tables, plus a Phase-1 set of shell keywords consumed first. Each command knows which flags take an argument (consume the next word) and which positional slots are mandatory, so the command word is found correctly through arbitrarily deep chains.
Shell keywords (Phase 1, consumed first): nocorrect, time (-p -l -v), -, builtin, command (-p), exec (-c -l -a NAME), eval, noglob, coproc.
External prefixes (Phase 2): sudo, doas, env, nice, nohup, rlwrap, timeout, strace, ltrace, ionice, caffeinate, setsid, chrt, taskset, watch, runuser, flock, chroot, unshare, cpulimit, su, stdbuf, sg, choom, nsenter, numactl, prlimit, setpriv, setarch, linux32, linux64, runcon, xvfb-run, chpst, cgexec, trickle, faketime, proot, bwrap, capsh, valgrind, fakeroot, unbuffer, chronic, torsocks, proxychains4, daemonize, firejail, sem, systemd-run, nocache, fakechroot, ccache, distcc, pkexec, torify, dbus-run-session, dbus-launch, eatmydata, tsocks, catchsegv.
All prefixes accept \escaped, 'single-quoted', and "double-quoted" forms; sudo/doas/env/nice/time/nohup/rlwrap are matched case-insensitively. Variable assignments (X=1, PATH=/usr/bin) are stripped at any position:
X=1 sudo gco => X=1 sudo git checkout sudo X=1 env Y=2 gco => sudo X=1 env Y=2 git checkout env FOO=bar BAZ=qux gco => env FOO=bar BAZ=qux git checkout strace -e trace=network gco => ...git checkout (= not stripped) su gco => su gco (gco fills USER slot, no expand) su root gco => su root git checkout
Custom corrections
The correction dictionary is a plain associative array. Key = the correct word, value = a space-separated list of misspellings. Add entries after the plugin loads, then rebuild the O(1) reverse lookup. Underscores in a key expand to spaces (hello_world → hello world).
# map misspellings to the correct word ZPWR_EXPAND_CORRECT_WORDS[kubernetes]="k8ss kuberntes kuberneets" ZPWR_EXPAND_CORRECT_WORDS[terraform]="terrafrom terrafomr" # append to an existing built-in entry ZPWR_EXPAND_CORRECT_WORDS[echo]+=" oech" # remove a built-in correction unset 'ZPWR_EXPAND_CORRECT_WORDS[background]' # rebuild the reverse lookup table after any changes zpwrExpandRebuildCorrectReverse
Tabstop snippets
Define aliases with $ZPWR_TABSTOP placeholders to turn them into IDE-style snippets. On expansion the cursor jumps to the placeholder instead of the end of the line.
alias gc="git commit -m ${ZPWR_TABSTOP}"
alias gca="git commit --amend -m ${ZPWR_TABSTOP}"
gc<space> => git commit -m | (cursor lands here)
Correct-then-expand & quote-aware expansion
With ZPWR_CORRECT_EXPAND=true, the spelling corrector fires first, then the corrected word is re-checked for alias expansion — all before the space is inserted, in one keypress.
With ZPWR_EXPAND_QUOTE_DOUBLE / ZPWR_EXPAND_QUOTE_SINGLE, aliases expand inside quoted strings in argument position. Quoted words at command position are never expanded.
echo "gco<space>" => echo "git checkout " (argument — expanded) "gco"<space> => "gco" (command position — not expanded)
Suffix alias expansion
With ZPWR_EXPAND_SUFFIX=true, suffix aliases (alias -s) expand at command position. Works with history injection — the expanded form is saved on accept-line.
alias -s txt=vim alias -s py=python alias -s json=jq file.txt<space> => vim file.txt script.py<space> => python script.py ./data.json<space> => jq ./data.json
History injection
With ZPWR_EXPAND_TO_HISTORY=true, the fully-expanded form is written into history while the typed (unexpanded) form is never written to $HISTFILE — same expansion rules as spacebar, so sudo gco lands in history as sudo git checkout. Pair with ZPWR_EXPAND_PRE_EXEC_NATIVE=true to also expand globs / params / history on accept-line.
Debug widget
Press Ctrl+Opt+E (Esc-Ctrl-E) to inspect the parser's view of the line without expanding anything — the parsed prefix chain, the identified command position, the action that would fire, and whether the command word exists. Useful for diagnosing why something is or isn't expanding.
┌── zsh-expand debug ────────────────┐ │ input: sudo -kE -u root gco │ │ prefix: sudo -kE -u root │ │ command: gco │ │ action: alias -> git checkout │ │ valid: no (gco not found) │ └────────────────────────────────────┘
Expansion preview
With ZPWR_EXPAND_PREVIEW=true, ghost text shows what the last word would expand to as you type, before pressing space — covering regular aliases, global aliases, suffix aliases, and spelling corrections. Press space to commit, keep typing to dismiss. Disabled by default because it shares the zle -M message area with other plugins; the hook chains onto any existing zle-line-pre-redraw and fires on the existing redraw cadence (no polling).
gco → git checkout
Expansion stats
Every expansion is logged to a stats file. zpwrExpandStats renders a cyberpunk dashboard with per-trigger and per-type tallies, total keystrokes saved, and the top aliases as proportional bar charts. Spacebar (S:) and history accept-line (H:) expansions are counted separately. Stats persist across sessions in $ZPWR_EXPAND_STATS_FILE (defaults under $ZPWR_LOCAL / $XDG_CACHE_HOME / ~/.cache); the parent directory is created on first write.
-h, --help | show the dashboard help |
-t, --top <N> | top N aliases (default 20, or $ZPWR_EXPAND_STATS_TOP) |
-w, --width <N> | box width (default 70) |
-c, --color | force ANSI colors |
-r, --reset | clear all stats |
-f, --file <PATH> | override the stats file path |
Command-position parser
Instead of one ever-growing regex, zpwrExpandParserFindCommandPosition walks the word array left-to-right and understands shell grammar in two phases: Phase 1 consumes shell keywords, Phase 2 consumes privilege-escalation prefixes and command wrappers. Each command has its own case branch that knows which flags take arguments and which positional slots are mandatory, so flag values containing = (e.g. strace -e trace=network) are not mistaken for variable assignments, and mandatory positional args (su→USER, chroot→PATH, timeout→DURATION) are never mistaken for the command. The parser exposes two results: ZPWR_VARS[cachedRegexMatch] (command + args after all prefixes) and ZPWR_VARS[cachedParserPrefix] (everything consumed as prefix).
Troubleshooting
| An alias won't expand | Check it isn't in ZPWR_EXPAND_BLACKLIST; press Ctrl+Opt+E to see the parser's command position and action. |
| Nothing expands at all | ZPWR_EXPAND=false disables the space/accept-line widget entirely (it returns immediately). Set it to true. |
Expansion after sudo not firing | Set ZPWR_EXPAND_SECOND_POSITION=true. |
| Valid command got "corrected" | By design real commands/functions are left alone; if you see a correction, the word isn't a resolvable command on $PATH. |
| Preview ghost text missing | It's off by default; set ZPWR_EXPAND_PREVIEW=true (may conflict with other plugins' zle -M output). |
| Custom correction ignored | Run zpwrExpandRebuildCorrectReverse after editing ZPWR_EXPAND_CORRECT_WORDS. |
Versus the competition
The README contains a full comparison matrix vs zsh-abbr, zsh-abbrev-alias, and OMZ globalias. zsh-expand is the only plugin in that set that uses native alias/global alias and parses prefix chains with flag awareness, ships a built-in correction dictionary, suffix-alias expansion, tabstop snippets, self-referential escape, correct-then-expand, history injection, live preview, expand-inside-quotes, and case-insensitive prefix matching — pinned by 11,688 tests, where two of the three siblings ship no test suite.
Performance
Apple Silicon, 10,000 iterations: file.txt suffix alias ~31 µs; sudo file.txt prefix+suffix ~130 µs; gco regular alias ~36 µs. Human perception threshold is ~100 ms — these are 770-3200x below it. Hot path uses zero external commands and zero subshells.
Sibling plugins
Part of the MenkeTechnologies zsh plugin family — the MenkeTechnologiesMeta umbrella:
- zsh-better-npm-completion — cache-aware
npm installcompletion - zsh-cargo-completion — live
cargo add/cargo installcompletion - zsh-cpan-completion — live MetaCPAN
cpan/cpanmcompletion - zsh-dotnet-completion — dotnet CLI completion
- zsh-gem-completion — ruby
gem installremote completion - zsh-git-acp — 159 git aliases + add/commit/push keybindings
- zsh-git-repo-cache — index every git repo on disk
- zsh-learn — MySQL-backed learning collection / quiz
- zsh-more-completions — 39,075-file mega completion corpus
- zsh-nginx — nginx commands + service-wrapper aliases
- zsh-pip-description-completion — pip remote completion with descriptions
- zsh-sed-sub — in-place sed substitution on the command line
- zsh-sudo — ESC ESC to prepend sudo
- zsh-xcode-completions — xcodebuild / xcrun / swift completion