Created
April 30, 2025 18:39
-
-
Save jcmosc/83a37f524ba77e60db1338494962c496 to your computer and use it in GitHub Desktop.
Temporarily print standard output to a custom text output stream in Swift
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
import Foundation | |
/// Additionally writes any data written to standard output into the given output stream. | |
/// | |
/// - Parameters: | |
/// - output: An output stream to receive the standard output text | |
/// - encoding: The encoding to use when converting standard output into text. | |
/// - body: A closure that is executed immediately. | |
/// - Returns: The return value, if any, of the `body` closure. | |
func printingStandardOutput<T>(to output: inout TextOutputStream, encoding: String.Encoding = .utf8, body: () -> T) async -> T { | |
var result: T? = nil | |
let consumer = Pipe() // reads from stdout | |
let producer = Pipe() // writes to stdout | |
let stream = AsyncStream<Data> { continuation in | |
let clonedStandardOutput = dup(STDOUT_FILENO) | |
defer { | |
dup2(clonedStandardOutput, STDOUT_FILENO) | |
close(clonedStandardOutput) | |
} | |
dup2(STDOUT_FILENO, producer.fileHandleForWriting.fileDescriptor) | |
dup2(consumer.fileHandleForWriting.fileDescriptor, STDOUT_FILENO) | |
consumer.fileHandleForReading.readabilityHandler = { fileHandle in | |
let chunk = fileHandle.availableData | |
if chunk.isEmpty { | |
continuation.finish() | |
} else { | |
continuation.yield(chunk) | |
producer.fileHandleForWriting.write(chunk) | |
} | |
} | |
result = body() | |
try! consumer.fileHandleForWriting.close() | |
} | |
for await chunk in stream { | |
output.write(String(data: chunk, encoding: encoding)!) | |
} | |
return result! | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment