Skip to content

Introduce PTY support#227

Open
iCharlesHu wants to merge 1 commit intoswiftlang:mainfrom
iCharlesHu:charles/pty
Open

Introduce PTY support#227
iCharlesHu wants to merge 1 commit intoswiftlang:mainfrom
iCharlesHu:charles/pty

Conversation

@iCharlesHu
Copy link
Copy Markdown
Contributor

@iCharlesHu iCharlesHu commented Mar 18, 2026

This PR introduces PTY support to Subprocess on Linux and Darwin. Now you can spawn processes in PTY mode with the two new run() overloads.

This API does NOT support Windows because Windows ConPTY did not support OVERLAPPED named pipes until Windows 11 24H2.

@iCharlesHu iCharlesHu requested a review from itingliu March 18, 2026 20:27
@iCharlesHu
Copy link
Copy Markdown
Contributor Author

Resolves: #175

This patch introduces two run overloads for spawning processes in PTY mode on Darwin and Linux
@iCharlesHu iCharlesHu marked this pull request as ready for review March 20, 2026 22:03
@iCharlesHu
Copy link
Copy Markdown
Contributor Author

We decided to drop Windows support for now because until very recently (Windows 11 24H2), ConPTY did not support overlapped named pipes. This means we can't have async IO with ConPTY.
See microsoft/terminal#262

@jakepetroules
Copy link
Copy Markdown
Contributor

This API does NOT support Windows because Windows ConPTY did not support OVERLAPPED named pipes until Windows 11 24H2.

Why omit the support, though? Could you just document the availability requirement and make it conditionally available given the right OS version?

If we get actual Windows availability at some point, we could also stick @available(Windows 10.0.26100, *) on it.

@jakepetroules
Copy link
Copy Markdown
Contributor

Something like:

guard ProcessInfo.processInfo.isOperatingSystemAtLeast(OperatingSystemVersion(majorVersion: 10, minorVersion: 0, patchVersion: 26100)) else {
    // FIXME: Add `@available(Windows 10.0.26100, *)` to the relevant declarations once the compiler supports Windows availability.
    preconditionFailure("PTY is not supported on this version of Windows.")
}

Note that the actual availability syntax exists, compiler-rt just doesn't implement the versioning, so if #available(Windows X, *) always returns false for any version.

} else if bytesRead == 0 || capturedErrno == EIO {
// We reached EOF. Return whatever's left

// On Linux, reading from a PTY parent returns EIO
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

) async throws -> SpawnPTYResult {
var termiosConfig = termios()
switch ptyOptions.terminalMode.storage {
case .cooked:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is "cooked" really the technical term of art here?

public struct PseudoterminalOptions: Sendable {
/// Terminal mode configuration.
///
/// On Darwin/Linux, this controls the initial `termios` settings applied to the
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Docs should say POSIX to be inclusive of BSDs

public var windowSize: WindowSize {
get throws {
var result = winsize()
guard ioctl(self.parentDescriptor, UInt(TIOCGWINSZ), &result) == 0 else {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can ioctl block for an indefinite amount of time for TIOCGWINSZ/TIOCSWINSZ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@iCharlesHu iCharlesHu added this to the Post 1.0 - Feature Release milestone Mar 23, 2026
@iCharlesHu
Copy link
Copy Markdown
Contributor Author

Punting this for post 1.0 for now. We do want to support Windows

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants