Skip to content

std/pty ​

Pseudoterminals: open one, spawn a program attached to it, and stream its output. This is the building block of terminal emulators, multiplexers and expect-style drivers. Each OS has its own implementation behind the one import path.

milo
from "std/pty" import { Pty, openAndSpawn, isInteractive }

API reference ​

std/pty has one implementation per target (darwin, linux, windows); the resolver picks the one for the target you build for.

Pty ​

milo
pub struct Pty

Fields: slavePath: string.

Pty.close ​

milo
fn Pty.close(self: &mut Pty): void

Idempotent: closing the master also unwedges a child blocked writing to a full PTY buffer (its write returns EIO), letting a pending SIGKILL land.

Pty.kill ​

milo
fn Pty.kill(self: &Pty): void

SIGKILL the child. Needed to tear down children that never exit on their own (e.g. while true shells) before a blocking wait().

Pty.open ​

milo
fn Pty.open(): Result<Pty, string>

Opening is one record (pty.open): the master fd and the slave's path. Under replay no pty exists and the master is a synthetic fd answered from the trace.

Pty.output ​

milo
fn Pty.output(self: &Pty): Channel<string>

Pump this pty's output on a background green task and return a channel of raw output chunks. The caller only recvs the channel — no read(), EAGAIN handling, or hand-written pump loop. The channel is closed when the child exits (read returns <= 0). This is node-pty's .onData ergonomics with green-task semantics underneath.

Pty.pid ​

milo
fn Pty.pid(self: &Pty): i32

The spawned child's pid, or -1 before spawn.

Pty.read ​

milo
fn Pty.read(self: &Pty, buf: *u8, len: i64): i64

Low-level single read into a raw buffer. Prefer output() for streaming — it owns the read/EAGAIN pump and hands you an iterable channel of chunks.

Pty.resize ​

milo
fn Pty.resize(self: &mut Pty, rows: u16, cols: u16): i32

Pty.spawn ​

milo
fn Pty.spawn(self: &mut Pty, program: &string, args: &Vec<string>): Result<i32, string>

Spawn child connected to PTY. Recorded as pty.spawn (the pid); under replay nothing is forked.

Pty.wait ​

milo
fn Pty.wait(self: &Pty): i32

Wait for child to exit. Returns exit status.

Pty.winSize ​

milo
fn Pty.winSize(self: &Pty): WinSize

Pty.write ​

milo
fn Pty.write(self: &Pty, buf: *u8, len: i64): i64

Pty.writeOnce ​

milo
fn Pty.writeOnce(self: &Pty, s: &string): i64

One write(2) of s, never retried and never parked: returns the bytes the master took (possibly fewer than s.len), or -1. Once the master is non-blocking (output() and any green read make it so), a full input queue returns -1 at once instead of waiting for the child to drain it, which is what a task that must keep serving other requests wants; write() parks.

Pty.writeStdout ​

milo
fn Pty.writeStdout(self: &Pty, s: &string): i64

WinSize ​

milo
pub struct WinSize

Fields: rows: u16, cols: u16, xpixel: u16, ypixel: u16.

Functions ​

isInteractive ​

milo
pub fn isInteractive(): bool

Returns true if stdin is a terminal (process is interactive).

isTerminal ​

milo
pub fn isTerminal<T: AsFd>(h: &T): bool

Returns true if h is connected to a terminal: isTerminal(Stdout {}).

openAndSpawn ​

milo
pub fn openAndSpawn(program: &string, args: &Vec<string>): Result<Pty, string>

Convenience: open + spawn in one call

tiocgwinsz ​

milo
pub fn tiocgwinsz(): i64

Only on darwin, linux.

tiocsctty ​

milo
pub fn tiocsctty(): i64

Only on darwin, linux.

tiocswinsz ​

milo
pub fn tiocswinsz(): i64

Only on darwin, linux.