Skip to content

Fix stdout buffering to enable streaming output#499

Open
prateek wants to merge 2 commits intocpisciotta:mainfrom
prateek:cursor/streaming-output-a25e
Open

Fix stdout buffering to enable streaming output#499
prateek wants to merge 2 commits intocpisciotta:mainfrom
prateek:cursor/streaming-output-a25e

Conversation

@prateek
Copy link
Copy Markdown

@prateek prateek commented Apr 13, 2026

Fixes #481 (Request: streaming output).

Problem

When xcbeautify is piped to another process (the typical usage: xcodebuild ... | xcbeautify | ...), the C runtime defaults to full buffering for stdout. Since the CLI used print() for all output, lines accumulated in a ~4 KB buffer before being flushed to the downstream consumer. This meant CI agents, log watchers, or other tools couldn't see results as they were produced; they had to wait for the buffer to fill or for the process to exit.

Solution

Add setvbuf(stdout, nil, _IONBF, 0) at process start to disable C stdio buffering on stdout. This is a single-line fix that makes all existing print() calls flush immediately, with no other code changes needed.

Uses @preconcurrency import Foundation to satisfy Swift 6 strict concurrency for the global stdout symbol.

Why setvbuf over the alternatives

Approach Tradeoff
setvbuf(stdout, nil, _IONBF, 0) (chosen) One line, uses standard print(), single I/O layer, no error handling needed
POSIX write(STDOUT_FILENO, ...) Bypasses stdio entirely but mixes two I/O layers on the same fd, requires manual partial-write and EINTR handling
fflush(stdout) after each print Requires touching every output site; easy to miss one

Changes

  • Sources/xcbeautify/Xcbeautify.swift: add setvbuf(stdout, nil, _IONBF, 0) at the top of run() and use @preconcurrency import Foundation
  • tools/test-streaming: add a CLI streaming test using FIFO-to-FIFO reads with read -t to verify each line flushes immediately
  • tools/cli-tests: integrate the streaming test into the existing CLI suite

Testing

  • swift test
  • swift build --configuration release -Xswiftc -warnings-as-errors
  • ./tools/lint
  • ./tools/cli-tests

Disable stdout buffering with setvbuf so xcbeautify streams output immediately through pipes, and add a CLI test that verifies line-by-line flushing behavior.
@prateek prateek force-pushed the cursor/streaming-output-a25e branch from e11cdc4 to f536e13 Compare April 13, 2026 06:29
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses issue #481 by ensuring xcbeautify streams output immediately when its stdout is piped, rather than being delayed by C stdio full-buffering.

Changes:

  • Disable stdout buffering at CLI startup via setvbuf(stdout, nil, _IONBF, 0).
  • Add a FIFO-based streaming regression test (tools/test-streaming) and run it from the existing CLI test harness.
  • Add environment/setup notes to AGENTS.md (Cursor Cloud-specific).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
Sources/xcbeautify/Xcbeautify.swift Disables stdout buffering at process start (and adjusts imports for Swift 6 concurrency).
tools/test-streaming Adds an integration test to validate per-line flushing through pipes using FIFOs + timeouts.
tools/cli-tests Integrates the streaming test into the CLI test suite.
AGENTS.md Adds Cursor Cloud environment/tooling notes and CLI testing guidance.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Sources/xcbeautify/Xcbeautify.swift
Comment thread Sources/xcbeautify/Xcbeautify.swift
var junitReportFilename = "junit.xml"

func run() throws {
setvbuf(stdout, nil, _IONBF, 0)
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Comment thread tools/test-streaming
Comment on lines +25 to +33
# Start xcbeautify: reads from IN_FIFO, writes to OUT_FIFO.
"$BIN" --disable-logging --preserve-unbeautified < "$IN_FIFO" > "$OUT_FIFO" &
XCB_PID=$!

# Open the write side of IN_FIFO (keeps it open across iterations).
exec 3>"$IN_FIFO"

# Open the read side of OUT_FIFO.
exec 4<"$OUT_FIFO"
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Comment thread tools/test-streaming Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Prateek Rungta <prateek@users.noreply.github.com>
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.

Request: streaming output

2 participants