What's here
As of v0.4.0, the output layer, the command layer, and the help
engine are implemented and stable:
- Plain output —
out/err: one call, no parsing, no allocation for a string literal. The hot path stays cheap. - Three styling paths — a chainable
stylebuilder, inlineparsetags, and a nameddefine_tag/tagregistry. All three render to identical bytes for the same intent. - Full color — the eight standard names plus any 24-bit color via hex or RGB,
with graceful downgrade to 256- or 16-color terminals and clean fall-back to
plain text on pipes,
NO_COLOR, or the Windows console without ANSI. - Command tree — a recursive
Commandtree with arg/flag parsing and aliases, registered into anAppfrom anywhere (not justmain), with.hidden()and.requires_auth()flags and structured, non-panicking errors. - Help & version — auto-generated
--help/-h(top-level and per-command) and--version/-V, rendered through the output layer with injectable header/footer.
The auth seam (v0.5.0) lands next — see the ROADMAP.
Installation
[]
= "0.4"
Color is on by default. For a build that never emits escape sequences (the API stays complete; every styled value renders as its plain text):
[]
= { = "0.4", = false, = ["std"] }
Quick Start
use ;
// Plain output — the common case.
out;
err;
// Styling, three ways, all rendering to the same bytes for the same intent:
out; // builder
parse; // inline tags
define_tag; // named registry
out;
The three styling paths
The same styled line, produced three ways. The choice is ergonomic, not visual — the bytes are identical.
use ;
// 1. Builder — chain methods; the result is `Display`. Best for computed/one-off.
out;
// 2. Tags — one string with inline markup. Best when text and style live together.
parse;
// 3. Named registry — define the look once, reuse by name across the program.
define_tag;
out;
Tag grammar: <b>…</b> (bold), <u>…</u> (underline),
<c=VALUE>…</c> (color, where VALUE is a named color, #rrggbb, or r,g,b),
and </> to close the innermost tag. Tags nest; unrecognized tags print
literally, so parse never rejects input.
Colors and terminals
Colors are the eight standard names, plus any 24-bit value:
use ;
out;
out;
out;
The terminal's capability is detected once. A 24-bit color renders exactly on a
true-color terminal, downgrades to the nearest 256- or 16-color value where that
is all the terminal supports, and falls away to plain text when output is a pipe,
NO_COLOR is set, or the crate is built without color. CLICOLOR_FORCE
overrides detection and forces color on. The Windows console is handled behind the
same API — virtual-terminal mode is enabled automatically, with a plain-text
fall-back if it cannot be.
Commands
Build a recursive command tree, register commands into an App from anywhere, and
let parse resolve the invocation, parse arguments, and run the selected
command's handler:
use ;
let mut app = new;
app.register;
app.register;
let _ = app.parse;
Commands register from anywhere — a command built in a non-main module is
reachable and behaves identically, the limitation that made the predecessor
unusable. Give a command extra names with .alias("rm") / .aliases(["rm", "del"]);
aliases resolve to the canonical command. The parser handles the standard forms
(--long, --long=value, -s, -svalue, bundled -abc, positionals, --),
and malformed input becomes a structured ParseError: parse prints it and exits
2, never panicking; try_parse_from returns it instead. .hidden() keeps a
command invokable but out of help; .requires_auth() records the flag for the auth
seam (v0.5.0).
Help and version come for free. -h / --help renders styled help for the
app or any command (with your help_header / help_footer); -V / --version
prints App::version(...). App::help() renders the top-level help as a string
whenever you want it. Both exit 0 under parse; try_parse_from returns them
as ParseError::HelpRequested / VersionRequested control signals.
Feature flags
| Feature | Default | Description |
|---|---|---|
std |
yes | Standard library: terminal detection, the stdout/stderr writers, and the command layer. |
color |
yes | ANSI / styled output. Implies std. Disable for plain output (still complete). |
auth |
no | Reserved for the requires_auth command flag (v0.5.0); no effect yet. |
Examples
Runnable examples live in examples/:
Force color when output is captured, or disable it, to see both paths:
CLICOLOR_FORCE=1
NO_COLOR=1
Performance
The plain path is allocation-free for a string literal — proven by a
counting-allocator test (tests/allocation.rs), not asserted. Local Criterion
means (Windows x86_64, release build):
| Operation | ns/op |
|---|---|
out plain write (&str) |
~10 |
| builder render, named color + bold | ~50 |
| builder render, 24-bit color | ~75 |
| named-registry render | ~43 |
Styling costs more than the plain path because it builds an owned String and
encodes escape sequences — a cost paid only when you opt into color. Reproduce
with cargo bench --bench bench.
Status
v0.4.0 ships the help engine (plus aliases and version) on top of the command
and output layers, per the ROADMAP and
docs/API.md. The auth seam (v0.5.0) follows; the public API
freezes at 1.0.0.
Contributing
See dev/DIRECTIVES.md for engineering standards and the definition of done. Before a PR: cargo fmt --all, cargo clippy --all-targets --all-features -- -D warnings, and cargo test --all-features must be clean.