terminal/pty.lisp
A child PTY and the serialized IO path which drives one Ghostty terminal.
The worker, mailbox, and terminal lock realize the single-owner flow in #K3KFGZ; the device deliberately does not own the semantic terminal.
Enqueue owned input octets for device's child process.
UTF-8 encode text and enqueue it for device's child process.
Enqueue one semantic Ghostty key event for device's child process.
Encoding happens on the PTY owner against the terminal's then-current modes.
Serialize a matching Ghostty and PTY window resize on device's IO owner.
Call function with device's terminal while excluding PTY mutation.
Return readable PTY octets, EOF status, and stream-error status.
A closed PTY master reports EIO on Linux instead of an ordinary zero-length read. Preserve any bytes collected earlier in this drain before publishing EOF.
Restore the ordinary terminal-driver echo disabled by RUN-PROGRAM :PTY.
Interactive terminal children expect to inherit ECHO initially. They remain free to disable it themselves for password entry, full-screen programs, or other private input modes.
SB-POSIX declares ioctl's third argument with the native variadic ABI.
Passing the CFFI pointer through its alien view matters on arm64 Darwin.
Neither operation can interleave with a read or another command. The child sees the kernel size before Ghostty publishes the matching grid.
Child exit and master EOF are not ordered: a fast child can be reaped just before its final output becomes readable. Drain any bytes first, then accept either process exit or the PTY's EOF.
Fork program under a fresh controlling PTY and return its child and stream.
Everything the child needs was allocated before FORKPTY; cross the post-fork window with only libc calls.
Close everything above the terminal FORKPTY just gave us. A shell in the wall would otherwise inherit every descriptor the image holds, and the one that hurts is the Slynk listening socket: an orphaned shell keeps the port bound long after its image is gone, so ./sly finds a port that accepts connections, answers no handshake, and refuses to start a replacement. A terminal has no business holding its parent's sockets open.
The table size is a soft limit, not a census: a shell whose ulimit is a million must not pay a million syscalls to start. The image's own descriptors are small numbers, so a few thousand closes cover them.
Start program under a PTY whose output drives terminal.
The device owns its child, PTY stream, IO thread, and Ghostty response route;
it does not own terminal. All terminal mutation and PTY traffic are serialized
by the device's worker. Use call-with-pty-device-terminal for renderer-side
snapshot work which must not race mutation.
Ghostty has already copied its borrowed callback data. The mailbox transfer keeps the callback quick and non-reentrant.
Wait for device's owner to finish; return its state or :timeout.
Stop device cooperatively, release its child and descriptor, and join it.
Logical disjunction of tests and raw truth values.
A child PTY and the serialized IO path which drives one Ghostty terminal. The worker, mailbox, and terminal lock realize the single-owner flow in #K3KFGZ; the device deliberately does not own the semantic terminal.
An explicitly owned libghostty-vt terminal.
An explicitly owned reusable libghostty-vt keyboard encoder and event.
(device)(device)(device)(bytes &key (start 0) end)Multiplication and scalar scaling.
Test whether one compatible scalar is at most another.
Subtraction or unary negation.
(device bytes &key (start 0) end)(device text)(device action key
&key modifiers consumed-modifiers text unshifted-codepoint composing-p)Enqueue one semantic Ghostty key event for DEVICE's child process. Encoding happens on the PTY owner against the terminal's then-current modes.
One named verb over a session.
Logical conjunction of tests and raw truth values.
(device columns rows &key (cell-width-pixels 0) (cell-height-pixels 0))(device function)(stream bytes)(stream &optional (capacity 4096))Test whether one compatible scalar is less than another.
Test whether two compatible scalars are equal.
(stream)Restore the ordinary terminal-driver echo disabled by RUN-PROGRAM :PTY. Interactive terminal children expect to inherit ECHO initially. They remain free to disable it themselves for password entry, full-screen programs, or other private input modes.
(stream columns rows cell-width-pixels cell-height-pixels)The minimum of compatible quantities.
(device message)(encoder terminal action key
&key modifiers consumed-modifiers text unshifted-codepoint composing-p)Encode one physical key fact using TERMINAL's current keyboard modes. ACTION is :PRESS, :REPEAT, or :RELEASE. KEY is a Ghostty/W3C physical key keyword. MODIFIERS use :SHIFT, :CONTROL, :ALT (or :META), and :SUPER. TEXT is layout-produced printable text; UNSHIFTED-CODEPOINT is its base codepoint.
(terminal columns rows &key (cell-width-pixels 0) (cell-height-pixels 0))(device)(child &optional no-hang-p)(process)Logical negation of one test or raw truth value.
(process timeout)Addition over compatible quantities.
Test whether one compatible scalar is at least another.
(device close-requested-p)(terminal function)Route terminal-generated response octets to FUNCTION, or disable with NIL. FUNCTION is called synchronously during WRITE-TERMINAL or WRITE-TERMINAL-BYTES. Its octet vector is an owned copy of Ghostty's borrowed callback bytes. FUNCTION must enqueue or copy promptly and must not feed the same terminal recursively.
(encoder)(device)(terminal bytes &key (start 0) end)(environment term)Test whether one compatible scalar is greater than another.
(name environment)(path)(program environment directory)(strings)(vector pointers)(program arguments directory environment columns rows)(terminal &key
(program (or (uiop:getenv "SHELL") "/bin/sh"))
arguments directory environment
(term "xterm-256color") on-output)Start PROGRAM under a PTY whose output drives TERMINAL. The device owns its child, PTY stream, IO thread, and Ghostty response route; it does not own TERMINAL. All terminal mutation and PTY traffic are serialized by the device's worker. Use CALL-WITH-PTY-DEVICE-TERMINAL for renderer-side snapshot work which must…
(terminal)(terminal)(device &key (timeout 5.0))(device &key (timeout 2.0))libghostty-vt does not pull bytes from a process. Luv creates a PTY, starts a child, reads the master descriptor when ready, and passes each byte slice to ghostty_terminal_vt_write. Feeding bytes mutates the terminal immediately. It does not emit a damage callback; the host merely requests a later render update and…
A PTY process which drives one libghostty-vt terminal from one IO owner.