Repository navigation
feat(cli): draw color on a terminal only, with a test that piped output stays clean - #2319
Merged
Merged
Conversation
aicayzer
force-pushed
the
feat/cli-colour
branch
from
October 22, 2026 23:15
f9ddc29 to
40f8614
Compare
aicayzer
marked this pull request as ready for review
October 22, 2026 23:20
aicayzer
enabled auto-merge (squash)
October 22, 2026 23:20
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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=dumband--jsonnever carry the escape byte, so an agent reading the CLI through a pipe sees what it saw before.Closes #2311
Changes
style.rs. Color is drawn for a stream only if that stream is a terminal,NO_COLORis unset or empty,TERMis notdumb, and the command was not given--json. Each stream is judged alone. It uses plain escape codes: no new dependency.$ commandechoes ofmarfa server install,upgrade,startanduninstall(bold and dim); theMarfa <release> is running.line and the labels of the summary and ofserver status(green and bold, bold; red for a server that is not answering); the user code of themarfa loginapproval prompt (bold); andmarfa: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.--jsonalso turns off clap's own color for help and usage errors, which clap otherwise draws on a terminal. clap already honorsNO_COLORandTERM=dumb.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.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 --checkandpnpm format:checkpass.tests/colour.rsgives the binary a pseudo-terminal. Witness first: a refusal and--helpon a terminal contain the escape byte. Then, for help, a command's help, a usage error and a refusal: piped,NO_COLOR=1,TERM=dumband--jsonon a terminal contain none, an emptyNO_COLORstill draws (so theNO_COLORcase is not passing by accident), and standard output on a terminal with standard error piped leaves the refusal plain. A run with--jsonfailed first because clap drew its help in color; it is fixed here.tests/server.rsruns 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 underNO_COLOR,TERM=dumb,--jsonand piped has no escape byte.colour.rsfor its witness.marfa loginprompt 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
style.rsand the call sites. No data, security or contract behavior beyond the new statement.printable, which escapes the escape byte, so text from a server cannot add color.Checklist