Skip to content

[Feature] allow getting the same output as processed by a terminal #60

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
gsabran opened this issue Jun 5, 2025 · 1 comment
Open
Labels
enhancement New feature or request

Comments

@gsabran
Copy link

gsabran commented Jun 5, 2025

Is your feature request related to a problem? Please describe.
Processes that write to stdout/stderr can change the output displayed in a terminal with different control sequences.

For instance running swift test in a terminal will output a lot of intermediary lines that are removed progressively. What would be the best way to achieve something similar? Does this library provide the required input to do post-processing to get the desired output ?

Consider

let result = try await run(
    .path("/usr/bin/swift"),
    arguments: ["test"]
) { execution, inputIO, outputIO, errorIO in
    var contents = ""
    for try await chunk in errorIO {
        let string = chunk.withUnsafeBytes { String(decoding: $0, as: UTF8.self) }
        contents += string
    }
    return contents
}

content is something like

[0/1] Planning build
[1/1] Compiling plugin GenerateManual
Building for debugging...
[1/2161]
...
[3540/3541] Linking PackagesPackageTests
Build complete! (35.81s)

but in my terminal I eventually only see

[3540/3541] Linking PackagesPackageTests
Build complete! (35.81s)

Describe the solution you'd like
Either:

  • guidance on how to post process the buffer sequences to get the desired data from the existing library, ideally including for when merging stdout and stderr streams.
  • new APIs, like consolidatedOutput / consolidatedError that do the adequate transformation.
    I'm not sure which one is the most appropriate.

Describe alternatives you've considered
I tried looking for \r and ANSI control sequence in the string chunks received from stdout/stderr, but I could not find the necessary input to reproduce the behavior I'm looking for.

Additional context
Happy to answer any questions

@gsabran gsabran added the enhancement New feature or request label Jun 5, 2025
@iCharlesHu
Copy link
Contributor

Hi @gsabran! The .string output type, along with AsyncBufferSequence which allows you to stream output live, are designed to capture all output content. By design, they don't process the output in any way like a terminal might because in many cases, you would want the original unmodified output.

If you don't really care about the actual output content nor want to collect it as a whole, instead of streaming output, you could try to use the .fileDescriptor output type to allow the child process to directly write to your standard output. Something like

let stdout: FileDescriptor = .standardOutput
let stderr: FileDescriptor = .standardError
let echoResult = try await Subprocess.run(
    .path("/usr/bin/swift"),
    arguments: ["test"],
    output: .fileDescriptor(
        stdout,
        closeAfterSpawningProcess: false
    ),
    error: .fileDescriptor(
        stderr,
        closeAfterSpawningProcess: false
    )
)

This setup allows the swift test's output to be directly printed out from your standard output, allowing the terminal to perform output transformations, which should work with carriage returns.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants