Bun has separate APIs for opening a terminal process and rendering terminal
output. Bun.Terminal creates a PTY or ConPTY for a child process; the headless
screens parse terminal output without starting a process.
Run an interactive process
Use Bun.Terminal with Bun.spawn() when a
child process needs a TTY. It connects the process to a PTY on Linux and macOS,
or ConPTY on Windows.
Parse terminal output
Bun.TerminalScreen and Bun.RioTerminal are headless screens. Create one,
write terminal output to it, and read the rendered text or cell data:
import { Terminal as RioTerminal } from "bun:rio";
const screen = new RioTerminal({ cols: 80, rows: 24, scrollback: 1000 });
screen.write("hello\r\nworld");
console.log(screen.text());
The bun:rio module exports the same constructor as Bun.RioTerminal. It only
parses data supplied to write(); it does not create a PTY, spawn a shell, or
read host files. To display a child's output, pass that output to the screen.
The constructor accepts optional dimensions from 1 to 4096 columns and rows,
and a scrollback limit from 0 to 1,000,000 rows. Defaults are 80 columns, 24
rows, and 1,000 scrollback rows. resize(cols, rows) changes the screen size;
reset() clears its contents and pending terminal replies. text() returns
visible text, while text({ scrollback: true }) includes retained lines.
write() returns the number of input bytes consumed. cells() returns a
Uint32Array in row-major order, with four values per cell: code point,
foreground color, background color, and flags. takeReplies() drains replies
to terminal query sequences. The cols, rows, cursor, title, and
alternateScreen properties report the current screen state.
RioTerminal.cellText(col, row) returns the full grapheme at a visible cell's
zero-based column and row. It preserves combining marks, variation selectors,
and joined emoji sequences; a wide-character spacer cell returns an empty
string. Both coordinates must be integers within the current visible screen.
In contrast, cells() stores only the grapheme's first code point in its first
word; the spacer cell uses code point 32 and display width 0.
Bun.TerminalScreen remains available for existing applications using Bun's
built-in terminal parser. Use Bun.RioTerminal or bun:rio when you want Rio's
VT parser and grid.