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

79 lines
3.9 KiB
Markdown

## 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
```zero
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.