Files
wehub-resource-sync e7738de6d2
CI / Deep Native Runtime Cases (1/6) (push) Has been skipped
CI / Native Preflight (push) Failing after 1s
CI / Native Runtime Cases (1/2) (push) Failing after 0s
CI / Native Runtime Cases (2/2) (push) Failing after 1s
CI / Native Metadata Reports (push) Failing after 0s
CI / Native Direct Backend Artifacts (push) Failing after 0s
CI / Native Sanitizer Smoke (push) Failing after 1s
CI / Command Contract Snapshots (push) Failing after 1s
CI / Deep Conformance Suite (push) Has been skipped
CI / Graph Build Perf (push) Failing after 1s
CI / Deep Native Preflight (push) Has been skipped
CI / Deep Native Runtime Cases (2/6) (push) Has been skipped
CI / Deep Native Runtime Cases (3/6) (push) Has been skipped
CI / Conformance Suite (push) Failing after 1s
CI / Workspace Checks (push) Failing after 0s
CI / Deep Native Runtime Cases (5/6) (push) Has been skipped
CI / Deep Native Runtime Cases (6/6) (push) Has been skipped
CI / Deep Native Runtime Cases (4/6) (push) Has been skipped
CI / Deep Graph Build Perf (push) Has been skipped
chore: import upstream snapshot with attribution
2026-07-13 12:29:30 +08:00

3.9 KiB

When To Use std.pty

In Zerolang, use std.pty for hosted child processes that need terminal semantics instead of plain pipes. PTY children are useful for interactive CLIs, REPLs, shells, editors, pagers, and tools that change behavior when stdout is a terminal.

Runnable today:

API Return Notes
std.pty.spawn(command) ProcChild Starts an argv-style command attached to a pseudoterminal.
std.pty.spawnIn(command, cwd) ProcChild Starts a PTY child in a hosted working directory.
std.pty.spawnInEnv(command, cwd, env) ProcChild Starts a PTY child with a working directory and newline-separated KEY=value environment bindings.
std.pty.spawnArgs(program, args, cwd, env) ProcChild Starts a program path plus newline-separated argv entries attached to a pseudoterminal.
std.pty.valid(child) Bool Reports whether the handle currently names an open child slot.
std.pty.childValid(child) Bool Alias for std.pty.valid.
std.pty.running(child) Bool Polls the PTY child without blocking.
std.pty.wait(child) ProcStatus Waits for process exit and returns its status.
std.pty.kill(child) Bool Sends the child a termination signal on supported hosts.
std.pty.interrupt(child) Bool Sends the child an interrupt signal on supported hosts.
std.pty.close(child) Bool Closes the handle and remaining terminal resources.
std.pty.pid(child) i32 Returns the hosted process id for the child, or 0 when unavailable.
std.pty.read(child, buffer) Maybe<usize> Nonblocking read from the PTY master into caller storage.
std.pty.write(child, bytes) Maybe<usize> Nonblocking write to the PTY master.
std.pty.resize(child, columns, rows) Bool Sets the child terminal size on supported hosts.

Metadata labels:

  • effects: proc
  • allocation behavior: child handles may keep runtime-owned PTY output buffers while wait drains terminal output
  • target support: hosted targets with the proc capability
  • error behavior: spawn helpers return an invalid ProcChild handle on failure; read and write return null when no bytes can be transferred
  • ownership notes: ProcChild values name runtime-owned process slots; call wait when process status matters and close when the handle is no longer needed

Example

pub fn main(world: World) -> Void raises {
    let child: ProcChild = std.pty.spawnArgs("printf", "hello pty\n", ".", "")
    let resized: Bool = std.pty.resize(child, 80_usize, 24_usize)

    var storage: [64]u8 = [0_u8; 64]
    var saw_output: Bool = false
    var attempts: usize = 0
    while attempts < 20_usize && !saw_output {
        let read: Maybe<usize> = std.pty.read(child, storage)
        if read.has {
            let bytes: Span<u8> = std.io.written(storage, read.value)
            saw_output = std.str.contains(bytes, "hello pty")
        }
        if !saw_output {
            let slept: Bool = std.time.sleep(std.time.ms(10))
        }
        attempts = attempts + 1_usize
    }

    let status: ProcStatus = std.pty.wait(child)
    if resized && saw_output && std.proc.succeeded(status) {
        check world.out.write("pty ok\n")
    }
    let closed: Bool = std.pty.close(child)
}

Design Notes

std.pty returns the same ProcChild handle shape used by std.proc, but the underlying child is connected to a pseudoterminal master. PTY output is a single terminal byte stream: stderr is merged by the terminal, and std.pty.read reads from that stream. Targets without process support, including Windows hosts until their process runtime is implemented, reject PTY helpers before code generation. For short-lived programs, drain the PTY with std.pty.read before wait; some hosts report the terminal as closed once the child exits.

Use std.proc.spawnChild* for programs where separate stdout and stderr pipes matter. Use std.pty.spawn* for programs where terminal behavior matters.