// ZSH-EXPAND — THE WORLD'S MOST POWERFUL ZSH EXPANSION PLUGIN // 11,688 TESTS

zsh plugin · spacebar-triggered expansion · aliases · global aliases · suffix aliases · globs · 292 misspelling corrections · 62 prefix commands parsed with full flag awareness · pure zsh · sub-millisecond

GitHub Issues
// Color scheme

>_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.

11,688
@test blocks (zunit)
62
prefix commands parsed
292
built-in spell corrections
~36 µs
per regular alias expand
0
external commands in hot path

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 expansionregular aliases in command position and after sudo/env/builtin/command/exec/eval/noglob/nocorrect/nice/nohup/rlwrap/time — with full flag support
Global aliasglobal aliases expanded anywhere on the command line
Spelling correction292 built-in corrections, user-extensible via associative array
Native expansionglobs, $params, $(cmd), =(...), !history
Tabstop snippetsaliases with $ZPWR_TABSTOP placeholders — cursor jumps to placeholder
Self-ref escapealias git="hub" expands to \hub — no infinite recursion
Correct-then-expandtypo correction chains into alias expansion in one keypress
Quote-aware expansionoptional expansion inside "double" / 'single' quoted args
Suffix aliasfile.txt<space>vim file.txt via alias -s
Autopair integrationdelegates space insertion to zsh-autopair when present
History injectionoptionally writes the fully-expanded form into history
Debug widgetCtrl+Opt+E (Esc-Ctrl-E) shows parser state — prefix chain, command position, expansion action — without modifying the line
Expansion previewghost text shows pending expansion before space is pressed
Expansion statszpwrExpandStats 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

SpaceSupernatural expand + insert space
Ctrl+SpaceInsert literal space (bypass)
Ctrl+Opt+EDebug widget — show parser state without expanding

Expansion rules

Where each expansion class fires — and where it deliberately does not.

Alias in first wordexpanded
Alias after sudo/env/builtin/…expanded; prefix matching is case-insensitive (SUDO, Sudo, sUdO all work)
Word is a real command/functionnot corrected — valid commands are left alone
Global alias anywhere on lineexpanded
Misspelling anywhere on linecorrected
Globs, $params, !historyexpanded (when ZPWR_EXPAND_NATIVE=true)
Cursor directly after wordexpand
One space after word (menuselect)expand
Two spaces after wordbypass

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_worldhello 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, --helpshow the dashboard help
-t, --top <N>top N aliases (default 20, or $ZPWR_EXPAND_STATS_TOP)
-w, --width <N>box width (default 70)
-c, --colorforce ANSI colors
-r, --resetclear 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 expandCheck it isn't in ZPWR_EXPAND_BLACKLIST; press Ctrl+Opt+E to see the parser's command position and action.
Nothing expands at allZPWR_EXPAND=false disables the space/accept-line widget entirely (it returns immediately). Set it to true.
Expansion after sudo not firingSet 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 missingIt's off by default; set ZPWR_EXPAND_PREVIEW=true (may conflict with other plugins' zle -M output).
Custom correction ignoredRun 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: