>_EXECUTIVE SUMMARY
zsh-pip-description-completion is a #compdef completion plugin that registers against seven pip-binary aliases (pip, pip2, pip-2.7, pip3, pip-3.2, pip-3.3, pip-3.4) in a single declaration. It ships the full pip 8 subcommand surface (13 subcommands — install, download, uninstall, freeze, list, show, search, wheel, hash, help, plus deprecated bundle/unzip/zip) with hand-curated descriptions, full top-level flag coverage (proxy, retries, timeout, exists-action, cache-dir, trusted-host, cert, client-cert, etc.), and menu-inline version + description rendering — the killer feature. pip install <TAB> shells out to pip search $PREFIX, parses the 4-column output (name version_paren - desc), and feeds zsh's _describe a tag→description map where the description is "$version $desc". The user sees which version is current and what the package does in the completion menu before pressing Enter. A separate PyPI HTML-index cache layer (zsh-pip-cache-packages) curls https://pypi.org/simple/ and stores the parsed package name set in ~/.pip/zsh-cache for offline use. zsh-pip-clear-cache autoload rotates the cache when PyPI's index changes.
~ARCHITECTURE · FILE STRUCTURE
Three-layer plugin: #compdef consumer under src/, autoload helpers under autoload/ (cache management, name extraction, cache flush), and an entrypoint that wires both into fpath.
| Path | Lines | Role |
|---|---|---|
| src/_pip | 121 | #compdef pip pip2 pip-2.7 pip3 pip-3.2 pip-3.3 pip-3.4 — 7 binaries, one declaration; 13-entry _1st_arguments subcommand table; top-level flags (--proxy, --timeout, --retries, --cache-dir, etc.); per-subcommand case dispatch for search/install/freeze/uninstall/show |
| autoload/zsh-pip-cache-packages | 19 | Cache builder — curls $ZSH_PIP_INDEXES (default https://pypi.org/simple/), pipes through zsh-pip-clean-packages (sed name extraction from PyPI HTML anchors), sort -u, writes space-separated names to $ZSH_PIP_CACHE_FILE (default ~/.pip/zsh-cache) |
| autoload/zsh-pip-clean-packages | 4 | sed -n '/<a href/ s/.*>\([^<]\{1,\}\).*/\1/p' — one-line PyPI HTML-anchor → package-name extractor |
| autoload/zsh-pip-clear-cache | 5 | Removes $ZSH_PIP_CACHE_FILE and unsets in-shell piplist array |
| autoload/zsh-pip-test-clean-packages | ~10 | Self-test for the sed extractor against a frozen PyPI HTML fixture |
| zsh-pip-description-completion.plugin.zsh | 23 | ZSH_PIP_CACHE_FILE=~/.pip/zsh-cache; ZSH_PIP_INDEXES=(https://pypi.org/simple/); fpath=("${0:h}/src" $fpath); fpath+=("${0:h}/autoload"); autoload -Uz "${0:h}/autoload/"*(.:t) |
| Total source | ~182 | 6 files across src/ + autoload/ + entrypoint |
@COMPLETION COVERAGE
Full pip surface plus the menu-inline description feature that gives this plugin its name.
7 binary aliases, one #compdef
Zsh's #compdef directive accepts a space-separated list. One declaration #compdef pip pip2 pip-2.7 pip3 pip-3.2 pip-3.3 pip-3.4 registers the same completer against every Python-version-suffixed pip alias users actually have on their PATH (system pip, virtualenv pip, pyenv-shimmed pip, etc.). No need for symlinks.
13 subcommands with descriptions
install,download,uninstall,freeze,list,show,search,wheel,hash,help- Deprecated (still completable):
bundle,unzip,zip— explicitly marked(deprecated)in description so the user knows
Live pip install with version + desc
pip install <TAB> → __pip_search → pip search $PREFIX output parsed as name version_paren - desc → tmp_ary+=("${(q)name}:${(q)version} $desc"). The name:description pair feeds _describe; description renders as (version) description text inline in the menu. This is the feature that gives the plugin its name — you see what the package does before you install it.
Top-level flag surface
- Help/version:
-h/--help,-V/--version - Verbosity:
-v/--verbose↔-q/--quiet(mutex) - Network:
--proxy,--retries,--timeout,--trusted-host - Cert:
--cert,--client-cert - Cache:
--cache-dir,--no-cache-dir - Misc:
--log,--isolated,--exists-action,--disable-pip-version-check - Deprecated:
-E/--environment,-s/--enable-site-packages
Per-subcommand argument completion
install:-U/--upgrade,--user,-f/--find-links,-r/--requirement(_files),--no-deps,-e/--editable(dir-only via_files -/), packages via__pip_searchwith fallback to*.tar.gz/*.whlfile completionfreeze:-l/--localsearch:--indexfor custom PyPI URLuninstall/show:__pip_installed→pip freeze | cut -d '=' -f 1→_wanted installed_pkgs
HTML-index cache (offline)
__pip_all → zsh-pip-cache-packages → curl https://pypi.org/simple/ → sed name extraction → sort -u → ~/.pip/zsh-cache. Cached on first use; cleared with zsh-pip-clear-cache. Means offline tab completion works after one online warm-up.
#TEST COVERAGE
45 zunit @test cases across 6 files, plus 21 structural shell gates from the umbrella.
| Test file | @test count | What it pins |
|---|---|---|
| tests/t-plugin.zsh | 23 | Plugin-entrypoint surface — ZSH_PIP_CACHE_FILE + ZSH_PIP_INDEXES defaults pinned; fpath contains both src/ and autoload/; all 4 autoload helpers autoloaded via autoload -Uz; _pip file present with multi-binary #compdef line |
| tests/t-contract.zsh | 3 | Entrypoint stem matches plugin-dir basename; #compdef declaration covers all 7 pip aliases |
| tests/t-contract2.zsh | 6 | ZSH_ARGZERO self-locate idiom intact; fpath manipulation order (src/ first, autoload/ appended) |
| tests/t-contract3.zsh | 5 | Helper-function shape — __pip_search uses prefix-keyed cache name pip_${PREFIX}_cache; __pip_installed calls pip freeze | cut -d '=' -f 1; __pip_all guards on $+piplist |
| tests/t-contract4.zsh | 5 | Autoload contract — every autoload/ helper has a self-invoking last line (fn-name "$@"); zsh-pip-clean-packages sed regex matches PyPI HTML anchor format |
| tests/t-syntax.zsh | 3 | zsh -n parse-cleanness on entrypoint, src/_pip, and every autoload/ helper |
| Total | 45 | 6 zunit files |
// STRUCTURAL GATES (21 shell scripts)
Same 21-script umbrella gate-set: 9 docs/*.html gates + 4 README + 3 man-page + 2 tests/ + 2 workflows + 1 cargo (vacuous).
?KEY DESIGN DECISIONS
Five places this plugin diverges from the upstream OMZ pip plugin.
Version + description in the menu
Upstream OMZ pip completion offers bare package names. This plugin parses pip search's 4-column output and feeds _describe a description string of "$version $desc" — so pip install requests<TAB> shows the version and one-line description for every requests* match. Tab completion becomes a low-friction package-discovery surface.
7-binary #compdef in one line
Most plugins register one binary per #compdef, then symlink or duplicate. This plugin uses #compdef pip pip2 pip-2.7 pip3 pip-3.2 pip-3.3 pip-3.4 — zsh accepts the space-separated list natively. Means every Python-version-suffixed pip alias on the user's PATH (system, pyenv, conda, virtualenv) gets the same completion table with zero duplication.
Cache to ~/.pip/zsh-cache, not ~/.zcompcache
The PyPI HTML-index cache lives next to pip's own config (~/.pip/) rather than zsh's cache dir. Rationale: this is a pip-derived artifact, and the user might want to inspect/share/version it. ~/.zcompcache/ is for opaque zsh-internal caches; this plugin's cache is a human-readable space-separated word list.
HTML-index, not JSON API
PyPI offers both an HTML index (/simple/) and a JSON API. This plugin curls the HTML index because it's the canonical, never-deprecated, all-packages-in-one-response surface. The JSON API requires per-package queries. sed -n '/<a href/ s/.*>\([^<]\{1,\}\).*/\1/p' extracts every package name in one pipeline pass.
Separate __pip_search + __pip_all paths
__pip_search is for pip install <prefix> (live search, per-prefix cached). __pip_all is for contexts that need the entire PyPI corpus (autocompleting a bare pip install <TAB> with no prefix yet). Two code paths because the cost profiles differ — __pip_search is a network call per prefix, __pip_all is a one-time HTML-index download.