Skip to content

feat(cli): draw color on a terminal only, with a test that piped output stays clean - #2319

Merged
aicayzer merged 3 commits into
mainfrom
feat/cli-colour
Oct 23, 2026
Merged

aicayzer merged 3 commits into
mainfrom
feat/cli-colour

Conversation

@aicayzer

Copy link
Copy Markdown
Contributor

Summary

The lines people read now have bold and color on a terminal, and only there. A test runs the binary on a pseudo-terminal and shows that piped output, NO_COLOR, TERM=dumb and --json never carry the escape byte, so an agent reading the CLI through a pipe sees what it saw before.

Closes #2311

Changes

  • New style.rs. Color is drawn for a stream only if that stream is a terminal, NO_COLOR is unset or empty, TERM is not dumb, and the command was not given --json. Each stream is judged alone. It uses plain escape codes: no new dependency.
  • Used for: the step lines and $ command echoes of marfa server install, upgrade, start and uninstall (bold and dim); the Marfa <release> is running. line and the labels of the summary and of server status (green and bold, bold; red for a server that is not answering); the user code of the marfa login approval prompt (bold); and marfa: in front of a refusal on standard error (red). Every word is unchanged, and the padding after a label stays outside the bold so the columns line up with or without color.
  • --json also turns off clap's own color for help and usage errors, which clap otherwise draws on a terminal. clap already honors NO_COLOR and TERM=dumb.
  • No command rewrites a line or draws a counter, and none does now: the long ones (server install, export, restore) print one plain line per phase. The issue allows a counter on a terminal and this change does not add one, because the number of steps of an install depends on its answers.
  • Contract: device/no-escape-off-terminal, with a device fixture for the half a fixture can reach (no terminal).

Testing

  • cargo test -p marfa-cli, cargo clippy -p marfa-cli --all-targets -- -D warnings, cargo fmt --check and pnpm format:check pass.
  • tests/colour.rs gives the binary a pseudo-terminal. Witness first: a refusal and --help on a terminal contain the escape byte. Then, for help, a command's help, a usage error and a refusal: piped, NO_COLOR=1, TERM=dumb and --json on a terminal contain none, an empty NO_COLOR still draws (so the NO_COLOR case is not passing by accident), and standard output on a terminal with standard error piped leaves the refusal plain. A run with --json failed first because clap drew its help in color; it is fixed here.
  • tests/server.rs runs a real install on a pseudo-terminal against the stand-in Docker: bold step lines, green running line, bold labels, and the same words once the escapes are taken out. The same run under NO_COLOR, TERM=dumb, --json and piped has no escape byte.
  • The device fixture runs the binary with no terminal and finds none; it needs colour.rs for its witness.
  • Not tested: color in the marfa login prompt on a terminal (the sentence is a unit-tested function; a sign-in needs a server), Windows, and a terminal that reports color but cannot draw it.

Notes for reviewers

  • Review depth: a read of style.rs and the call sites. No data, security or contract behavior beyond the new statement.
  • Server text still goes through printable, which escapes the escape byte, so text from a server cannot add color.

Checklist

  • The title is a scoped Conventional Commit.
  • New behavior has a test that was seen failing first, or no test was needed and the reason is above.
  • Docs, comments and the contract still say what is true after this change.

@aicayzer
aicayzer marked this pull request as ready for review October 22, 2026 23:20
@aicayzer
aicayzer enabled auto-merge (squash) October 22, 2026 23:20
@aicayzer
aicayzer merged commit 889da4d into main Oct 23, 2026
35 checks passed
@aicayzer
aicayzer deleted the feat/cli-colour branch October 23, 2026 00:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

marfa: color and progress on a terminal only, with a test that piped output stays clean

1 participant