>_EXECUTIVE SUMMARY
zsh-very-colorful-manuals colorizes man pages by overriding the pager's termcap rendering. The plugin entry appends ${0:h}/bin to fpath and runs autoload -Uz man; the autoloaded bin/man defines a __man() helper that runs the system man through env with 7 LESS_TERMCAP_* escapes plus PAGER / _NROFF_U / PATH. less reads those escapes to render bold headers green, underlined option names bold-cyan, and standout text bright-magenta. The variables live only in the man subprocess — nothing is exported into the interactive shell. Source: 43 zsh lines across 1 plugin entry + 1 bin/man wrapper. Pinned by 48 @test blocks across 7 zunit files.
~ARCHITECTURE
Two files. The plugin entry is the install surface (fpath + autoload + Solaris shim creation); bin/man is the actual color-injecting wrapper, resolved by zsh's autoload mechanism the first time man is called.
| File | Lines | Role |
|---|---|---|
zsh-very-colorful-manuals.plugin.zsh |
24 | Plugin entry. On $OSTYPE = solaris*, writes a $HOME/bin/nroff shim (only if not already executable) that rewrites -u0 -Tlp -man to /usr/bin/nroff -u$_NROFF_U. Then the Zsh Plugin Standard 0= header resolves ${0:h} under zinit / oh-my-zsh / antibody / antigen / bare source; fpath+="${0:h}/bin" appends the wrapper dir (append, not assign — preserves existing fpath); autoload -Uz man registers the wrapper. |
bin/man |
19 | The color wrapper. Defines __man() which calls env with 7 LESS_TERMCAP_* escapes (each built via printf '\e[…m'), PAGER=${commands[less]:-$PAGER}, _NROFF_U=1, and PATH="$HOME/bin:$PATH", then runs the system man "$@". The file ends with __man "$@" so the autoloaded shadow invokes the helper. The helper is named __man (not man) so the inner man call hits the system binary — no recursion. |
| Total source | 43 | 1 entry + 1 wrapper · pure zsh, no compiled artifacts |
$COLOR CONTRACT
Every LESS_TERMCAP_* escape is built with printf '\e[CODEm' so a real 0x1b ESC byte (not the literal \e text) crosses the env boundary into less. The exact SGR code per key is pinned by the test suite; changing any one silently changes the palette. Below is the live mapping from bin/man.
| Termcap key | Role | SGR code | Color |
|---|---|---|---|
LESS_TERMCAP_md | bold start | 0;32m | green — section headers |
LESS_TERMCAP_me | bold end (reset) | 0;34m | blue |
LESS_TERMCAP_us | underline start | 1;36;4m | bold cyan + underline — option names |
LESS_TERMCAP_ue | underline end | 0;1;31m | bright red |
LESS_TERMCAP_so | standout start | 0;1;35m | bright magenta — (END) marker, search matches |
LESS_TERMCAP_se | standout end | 33m | yellow |
LESS_TERMCAP_mb | blink start | 0;33;44m | yellow on blue |
=ENVIRONMENT
Beyond the 7 LESS_TERMCAP_* keys, the env block carries three more variables into the man subprocess. None of these is exported in the parent shell — env scopes them to the single man invocation. The wrapper deliberately does not set LESS itself, leaving user-set less defaults intact.
| Variable | Value | Effect |
|---|---|---|
PAGER | ${commands[less]:-$PAGER} | Resolves zsh's commands hash for the absolute path to less, falling back to the user's $PAGER. Guarantees the page is rendered by a pager that honors LESS_TERMCAP_* (a PAGER=most user would otherwise lose the coloring). |
_NROFF_U | 1 | Read by the Solaris nroff shim to enable underline (EUC) mode. No effect on Linux/macOS — the shim only exists on Solaris. |
PATH | $HOME/bin:$PATH | Prepends $HOME/bin so the Solaris nroff shim (written by the plugin entry) shadows /usr/bin/nroff. Reversing the order would let system nroff win and drop the -u underline flag. |
#TEST COVERAGE
48 @test blocks across 7 zunit files. The bulk (t-man-wrapper.zsh, 19 tests) pins the exact SGR code per termcap key so a refactor can't silently change the palette; t-man-passthrough.zsh actually executes __man through a PATH-shimmed fake man and inspects the argv + environment the real man would receive. The contract files pin the install path (fpath append, autoload directive, entrypoint stem), the env-wrapper shape (env not exec/source, man "$@" passthrough, no LESS clobber, no parent-shell leak), and the Solaris shim. CI runs them under zunit.
| File | Tests | Pins |
|---|---|---|
t-man-wrapper.zsh | 19 | Exact SGR code per LESS_TERMCAP_* key (mb/md/me/se/so/ue/us); __man helper name (not man — recursion guard); env-wrapper (not exec/source); 7-key count; PAGER prefers commands[less]; _NROFF_U=1; PATH prepend; trailing __man "$@"; Solaris shim creation; fpath+= append; autoload -Uz man; whence -v man resolves; ≥11 continuation lines. |
t-man-passthrough.zsh | 2 | Behavioral: argv passes verbatim through env — spaces, globs, unicode, and $()-literal survive unsplit/unexpanded; LESS_TERMCAP_mb crosses the env boundary as a real 0x1b ESC byte (hexdump 1b5b303b33333b34346d), proving the printf evaluated. |
t-syntax.zsh | 5 | zsh -n over *.zsh + bin/man; sourcing extends fpath with bin/; bin/man exists and references ≥7 LESS_TERMCAP_* keys; PAGER wired to less. |
t-contract.zsh | 7 | Entrypoint stem matches dir basename; entrypoint parses; #compdef on any _* file; fpath augmented with bin; autoload man present; bin/man is a function file (no shebang); references LESS_TERMCAP_(md|us|so|me). |
t-contract2.zsh | 5 | bin/man basename is literally man; Solaris shim rewrites -u0,-Tlp,-man; no LESS= clobber; shim creation stays inside the Solaris branch; re-source doubles the fpath bin entry (current, unguarded behavior). |
t-contract3.zsh | 5 | Every LESS_TERMCAP_* value is a valid ANSI SGR sequence; no export of the escapes (env-only scope); zsh function NAME() shape; unquoted EOF heredoc (write-time interpolation); ends with plain man "$@". |
t-contract4.zsh | 5 | All 7 LESS_TERMCAP_* vars in the env block (by count); PAGER="${commands[less]:-$PAGER}" exact shape; _NROFF_U=1; PATH="$HOME/bin:$PATH"; trailing man "$@" passthrough. |
| Total | 48 | 7 zunit files · color-contract + env-wrapper shape + install-contract + Solaris shim |
/DESIGN DECISIONS
env-scoped, not exported
The escapes are passed via env LESS_TERMCAP_x=… man, not export. They apply only to the man subprocess; the parent shell's other less invocations keep their own (or no) coloring. An export would silently pollute every less the user runs.
__man not man
The inner helper is named __man. The autoloaded function shadows man for the user, but the call at the end of the env block is the bare system man. Naming the helper man would make the wrapper call itself — infinite recursion.
PAGER pins to less
${commands[less]:-$PAGER} resolves the absolute path to less from zsh's command hash, falling back to $PAGER. Without this, a user whose $PAGER ignores LESS_TERMCAP_* (e.g. most) would get no coloring at all.
fpath append, not assign
The entry uses fpath+="${0:h}/bin". Assigning (fpath=(…)) would wipe every other plugin's autoload directories. Append preserves them — at the cost that re-sourcing stacks duplicate entries (pinned as current behavior in t-contract2).
Solaris shim, conditional
Solaris nroff lacks the -u underline flag. The plugin writes a $HOME/bin/nroff shim — but only inside the $OSTYPE = solaris* branch, so Linux/macOS shells never create spurious files in $HOME/bin.
Verbatim argv passthrough
The wrapper ends with quoted man "$@". Titles with spaces (man "Tcl_NewObj"), glob characters, unicode, and command-substitution-looking literals all reach man unsplit and unexpanded — pinned by the passthrough test against a PATH-shimmed fake man.
@FOOTPRINT
- Disk: 2 source files (plugin entry +
bin/man), 43 lines total. No compiled artifacts. On Solaris, one generated$HOME/bin/nroffshim. - Startup cost: the 24-line entry parse plus
autoload -Uz man(lazy —bin/manbody is not parsed until the firstmancall). - Runtime cost: one
env+ one systemmansubprocess per invocation. No persistent state, no caches, no background process. - External tools: the system
man(required),less(the pager that readsLESS_TERMCAP_*; the wrapper prefers it over$PAGER), and on Solaris/usr/bin/nroffbehind the shim. - Side effects on the parent shell:
fpathgains thebin/directory;manbecomes an autoloaded function. No environment variables are exported — theLESS_TERMCAP_*escapes exist only inside eachmansubprocess.