Repository navigation
feat(cli): color help and error labels with one --color policy - #86
Conversation
tee8z
left a comment
There was a problem hiding this comment.
Approved 1db2da6 on its base, 520c775. The PR conflicts with current master in CHANGELOG.md and src/cli.rs, because #87–#95 merged after it was cut, so it needs a rebase before it can merge. A rebase dismisses this approval, and I will compare the trees again then.
The color policy is sound:
- The argv pre-scan stops at
--, the last--colorwins, and an invalid value falls back toauto. --no-colorand--colorconflict.- Help styles reach each subcommand through
app_ext. - The human error report is scrubbed before it is painted, so every escape comes from the palette, and the hostile-text unit test pins that.
- Redirected stderr goes through anstream's strip path, so its bytes are unchanged, and JSON output never passes through
style. - The environment docs match anstyle-query's handling of
NO_COLORandCLICOLOR_FORCE.
Nonblocking:
startup.rs:68builds the--jsonparse-error envelope fromerror.to_string()on a clap error that may be colored. It is plain today, becauseStyledStr'sDisplaydrops the styles. But the byte-identical JSON test covers only a runtime error. A case such asvoltage --json --color always paymntswithCLICOLOR_FORCE=1, asserting no ESC byte, would pin the parse path.docs/quality.mdassigns each concern to a module, and it has no entry for the newstylemodule.
Validation on this head, in nix develop: cargo fmt --check, cargo clippy --locked --all-targets -- -D warnings, cargo machete --with-metadata, cargo test --locked (135 unit, 122 integration) and python3 scripts/check-coverage.py passed. CRAP: 619 measured functions, none at or above 20, highest wait_for_payment at 19.60; 177 functions were unmeasured. CI is green on this head.
1db2da6 to
6c8a7f6
Compare
|
Rebased the whole stack onto master (#87–#95) and fixed the review findings on #91, #96, #98, #101, and #108. The rebase changed this PR's head, which reset its approval. The only conflicts were import lines in |
`--color auto|always|never` (and a hidden `--no-color`) decides; otherwise each stream follows anstream's automatic choice, which honors NO_COLOR, CLICOLOR_FORCE, CLICOLOR, TERM=dumb, and whether the stream is a terminal. clap's help and parse errors use the same choice and cargo-style 16-color styles. Only fixed labels are painted, so API text never carries an escape sequence, and JSON output is never colored.
tee8z
left a comment
There was a problem hiding this comment.
Re-approved 6c8a7f6, a rebase onto master 8dfa4ee. The patch matches 1db2da6, which I approved, and only the CHANGELOG context changed. It also merges cleanly with the current master (e134cf1, with #102). Validation on this head, in nix develop: the full gate passed (147 unit, 125 integration). CRAP: 646 measured functions, none at or above 20, highest wait_for_payment at 19.60. CI is green.
6c8a7f6 to
97e4ea1
Compare
|
A note on my approval: it was recorded on |
Stack position: 1 of 13 in the look-and-feel stack. Base:
master. Every later layer builds on thestylemodule this PR adds.Problem
The CLI's own output had no color. clap already colored help and parse errors on a terminal, so a mistyped flag printed a red
error:but an API error printed a plain one. No flag controlled either.Behavior
error:hint:details:(ours)--color always--color neveror--no-colorNO_COLOR=1CLICOLOR_FORCE=1--color auto|always|neverunder Output, plus a hidden--no-color. Auto uses anstream's exact rule, the one clap already used:NO_COLOR,CLICOLOR_FORCE,CLICOLOR,TERM=dumb, and whether each stream is a terminal.error:red bold,hint:cyan bold,details:dim. Only the label is colored, and the words are unchanged.style::paintaccepts only&'static strlabels, so API text cannot be styled. Every escape sequence comes from the palette, and a unit test checks this with hostile text (CSI, OSC 8, BEL).Design notes
docs/quality.mdforbids global state, so the code does not callanstream::ColorChoice::write_global. Startup pre-scans argv for--colorand--no-color, stopping at--(like the existing--jsonscan). It passes the result to clap throughCommand::colorand to our stderr throughanstream::AutoStream::new. After parsing, the typed flag decides runtime errors.anstream = "=1.0.0"directly. clap already depends on it, soCargo.lockgains one dependency edge and no crates. Styles use clap'sbuilder::stylingre-export of anstyle.eprintln!would panic if stderr was closed.FORCE_COLORis not honored. Its meaning is still an open question in the plan.Validation
cargo fmt --check,cargo clippy --locked --all-targets -- -D warnings,cargo machete --with-metadata(0.9.2),cargo test --locked(135 unit and 122 integration tests), andpython3 scripts/check-coverage.pyall pass.--color alwayswithCLICOLOR_FORCE=1, and check colored and plain help and parse errors.NO_COLOR,CLICOLOR, andCLICOLOR_FORCE, so a developer's environment cannot change the bytes the tests compare.src/api.rswait_for_payment, which this PR does not touch.--helpand a runtime error on a pseudo-terminal (script); both colored as described.Docs
docs/reference/output.md,environment.md(NO_COLOR,CLICOLOR_FORCE,CLICOLOR), the regeneratedglobal-flags.md, andCHANGELOG.md.