Fix console output rendering - #102
Open
graeme wants to merge 7 commits into
Open
Conversation
Homebrew strips ANSI colour when stdout isn't a TTY, which a Pipe never is, so the console panel only ever saw plain text. Set HOMEBREW_COLOR and CLICOLOR_FORCE on the subprocess environment when a console sink is observing the command, leaving parsed read commands (brew config, --json) untouched so their output stays clean for parsing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Parses the colour escape codes brew now emits into styled spans the console can render. Kept UI-free with a semantic ANSIColor enum so BrewCore gains no SwiftUI dependency; the view layer maps colours onto its palette. Scope is per-line, matching the console's one-row-per-line model. Cursor and screen-control sequences (the live progress UI) are stripped for now — interpreting them is a later TTY-backed step. Malformed and unsupported sequences are consumed rather than surfaced as literal text. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Map the parsed ANSI spans onto the console palette so brew's coloured output (blue ==> headers, green success, yellow warnings, red errors) renders in the panel instead of plain monospace. Uncoloured spans keep the stream's default colour, so lines without codes look unchanged. Exported and copied logs run through ANSIParser.plainText so on-disk output stays plain text. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
MikeMcQuaid
approved these changes
Jul 28, 2026
Remove comments that merely restated the code, keeping public API docs and the non-obvious ANSI-protocol facts (escape terminators, CSI final-byte range, reset semantics, extended-colour argument counts) that a future editor could break without understanding. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Test names starting with a digit trip SwiftLint's identifier_name rule; prefix the 256-colour test so it starts with a letter. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds ANSI SGR parsing and rendering so Homebrew’s colored output can be displayed in BrewUI’s console panel (instead of being stripped when stdout is not a TTY), while ensuring exported/copied logs remain plain text.
Changes:
- Forces color emission for streamed console runs by injecting
HOMEBREW_COLOR=1andCLICOLOR_FORCE=1only when a console output sink is active. - Introduces a UI-free
ANSIParserinBrewCorethat converts ANSI sequences into styled spans (foreground + bold) and strips unsupported/control sequences. - Updates console rendering to use
AttributedStringruns and updates export logic/tests to strip ANSI codes.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| Tests/BrewFeatureConsoleTests/CommandJobExportTests.swift | Adds coverage to ensure exported output strips ANSI sequences. |
| Tests/BrewFeatureConsoleTests/ANSIConsoleTextTests.swift | Adds tests verifying AttributedString rendering and run segmentation. |
| Tests/BrewCoreTests/ANSIParserTests.swift | Adds comprehensive unit tests for parsing SGR, resets, unsupported sequences, and plain-text stripping. |
| Sources/BrewFeatureConsole/Views/ConsoleBody.swift | Switches console rows to render attributed text rather than raw strings. |
| Sources/BrewFeatureConsole/Views/ANSIConsoleText.swift | Maps parsed ANSI spans to design-system colors and bold monospaced font runs. |
| Sources/BrewFeatureConsole/ViewModels/CommandJob+Presentation.swift | Strips ANSI before producing clipboard/export text. |
| Sources/BrewCore/Operations/ANSIParser.swift | Adds the ANSI parser and style/span model in the core layer. |
| Sources/BrewCLI/BrewCommandService.swift | Forces color env vars only for streamed console output (TaskLocal sink present). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
ESC[48;5;n and ESC[48;2;r;g;b were unhandled, so their arguments fell through and were parsed as independent SGR codes — a background palette index like 31 wrongly set a red foreground. Consume 48's arguments the same way as 38 without mutating the modelled style, and cover both the 256-colour and truecolour background forms with tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
PR: Render brew colour output in the console
Summary
Homebrew strips ANSI colour when its stdout isn't a TTY, and a
Pipenever is. So the console panel only ever showed flat monospace text. This PR forces colour on and renders it, giving the console the same colour cues (blue==>headers, green success, yellow warnings, red errors) a user sees in Terminal.Changes
BrewCommandServicesetsHOMEBREW_COLOR=1andCLICOLOR_FORCE=1on the subprocess only when a console sink is observing the command, leaving parsed read commands (brew config,--json) untouched so their output stays clean.ANSIParserinBrewCoreturns escape codes into styled spans (foreground colour + bold) via a semanticANSIColorenum; unsupported, 256-colour/truecolour, and cursor/screen-control sequences are consumed rather than surfaced as literal text.ANSIConsoleTextmaps parsed colours onto the design-system palette andConsoleBodyrenders anAttributedString; uncoloured spans keep the stream default so untouched lines look identical. Exported/copied logs run throughANSIParser.plainTextto stay plain text.Why this split
This is Stage 1 (colours only) of the "make console output render like a terminal" feedback. It's low-risk and self-contained. The live download/progress "UI" needs a real PTY and terminal emulation — deliberately deferred to a follow-up.
Testing
scripts/test‚ — full package suite greenBrewFeatureConsoleTestsswift buildcleanPR checklist
Follow-ups
\r/cursor handling to render in-place progress updates.