NAME
Term::Ghostty - Headless terminal emulator built on Ghostty's libghostty-vt
SYNOPSIS
use Term::Ghostty;
my $term = Term::Ghostty->new(
cols => 80,
rows => 24,
on_pty_write => sub {
my ($term, $bytes) = @_;
syswrite $pty, $bytes; # answers to terminal queries
},
on_title_changed => sub {
my ($term, $title) = @_;
print "title: $title\n";
},
);
$term->feed($bytes_read_from_a_pty);
$term->feed("Hello \e[31mGhostty\e[0m!\r\n");
my $text = $term->get_text; # visible screen
my $all = $term->get_text(scrollback => 1); # with history
my $vt = $term->get_vt(cursor => 1, style => 1);
my $html = $term->get_html;
my ($col, $row) = $term->cursor_pos;
my $fullscreen = $term->active_screen eq 'alternate';
$term->resize(100, 30);
DESCRIPTION
Term::Ghostty feeds a byte stream through the terminal emulation core of the Ghostty terminal, libghostty-vt, and lets you read back the resulting screen: its text, cursor and modes, or the screen re-encoded as plain text, VT sequences or HTML. There is no display; use it to drive or test programs running in a pseudo-terminal, to scrape their output, or to render captured terminal output.
The library comes from Alien::ghostty. When that module builds it, which is the default, it is linked statically.
CONSTRUCTOR
new
my $term = Term::Ghostty->new(%options);
Options:
- cols, rows
-
Size in cells, 1 to 65535. Default 80 x 24.
- cell_width_px, cell_height_px
-
Size of one cell in pixels, used only to answer pixel-size queries (
CSI 14 t) and in-band resize reports (mode 2048). Default 0. - max_scrollback
-
Roughly how many rows of history to keep. The library keeps and frees history in whole pages of a few hundred rows, so the number kept can be off by a page either way, and rows are counted at the current width. 0 disables the scrollback; undef keeps the default of about one page. Setting it also lifts the library's default memory cap, so memory use grows with the content.
- title, pwd
-
Initial window title and working directory.
- on_pty_write, on_title_changed, on_bell, on_pwd_changed
-
Callbacks, see "CALLBACKS".
It croaks on an unknown option, an odd number of arguments, an out-of-range size, or a callback that is not a code reference.
METHODS
feed
$term->feed($data);
Runs $data through the VT parser. A byte string is processed as raw bytes, which is what you read from a pseudo-terminal; a character string (one with the UTF-8 flag) is processed as its UTF-8 encoding. Escape sequences and multi-byte characters may be split across calls. Malformed UTF-8 shows up as U+FFFD.
The emulator does not turn "\n" into "\r\n"; a pseudo-terminal's line discipline normally does that. When feeding text from a file or a pipe, convert the line endings yourself or enable linefeed mode with "\e[20h".
write
Same as "feed".
write_until_ground
my ($consumed, $at_ground) = $term->write_until_ground($data);
my $consumed = $term->write_until_ground($data);
Feeds only the shortest prefix of $data that brings the parser back to its ground state, the point between sequences where it is safe to inject your own output. $consumed is the number of bytes processed (of the UTF-8 encoding, for a character string, so split byte strings rather than character strings with it); the rest of $data is not processed, so feed it yourself. If the parser is already at ground, nothing is consumed. $at_ground is false when all of $data was consumed and the parser is still inside a sequence.
format
my $out = $term->format(%options);
Returns the screen as a character string. Rows are joined with "\n" ("\r\n" for VT output); rows below the last one written to are omitted and rows are not padded to the terminal width.
- format => 'plain' | 'vt' | 'html'
-
Plain text (the default), text with the VT sequences needed to reproduce its colours and attributes, or HTML. See "HTML OUTPUT".
- scrollback => 0 | 1
-
Include the scrollback history before the visible screen. Default 0.
- trim => 0 | 1
-
Remove trailing spaces from each row of plain output. Default 1.
- unwrap => 0 | 1
-
Join rows that were soft-wrapped at the right margin. Default 0.
- palette => 0 | 1
-
Include the colour palette: a
<style>block for HTML (default 1), OSC 4 sequences for VT (default 0).
The following options add terminal state to VT output, so that replaying it into a fresh terminal restores more than the text. They all default to 0: cursor (cursor position), style (the current SGR attributes), modes, scrolling_region, tabstops, pwd, keyboard, hyperlink, protection, kitty_keyboard and charsets.
It croaks on an unknown option or an odd number of arguments.
get_text
my $text = $term->get_text(%options);
Same as format(%options, format => 'plain').
get_vt
Same as format(%options, format => 'vt').
get_html
Same as format(%options, format => 'html').
cols
The terminal width in cells.
rows
The terminal height in cells.
cursor_x
The cursor column, counted from 0.
cursor_y
The cursor row, counted from 0 at the top of the visible screen.
cursor_pos
my ($col, $row) = $term->cursor_pos;
my $pos = $term->cursor_pos; # [$col, $row]
cursor_visible
True unless the cursor was hidden (DEC mode 25).
cursor_pending_wrap
True if the cursor is in the last column and the next character will wrap.
title
my $title = $term->title;
The window title, set by OSC 0 or OSC 2 or by "set_title". An empty string when there is none.
set_title
$term->set_title($title);
Sets the title; undef clears it. Does not call on_title_changed.
pwd
my $url = $term->pwd;
The working directory as reported by the program, usually through OSC 7. This is the raw value from the escape sequence, normally a URL such as file://host/home/me/My%20Dir, not a decoded path. An empty string when there is none.
set_pwd
$term->set_pwd($url);
Sets the working directory; undef clears it. Does not call on_pwd_changed.
resize
$term->resize($cols, $rows);
$term->resize($cols, $rows, $cell_width_px, $cell_height_px);
Changes the size. Text on the primary screen is reflowed. The cell pixel size is kept when not given. If the program enabled in-band resize reports (mode 2048), the report is sent through on_pty_write during this call.
reset
Full reset (RIS): clears both screens and the scrollback, and restores the default modes, attributes, title and working directory. Callbacks and the size are kept.
mode
my $on = $term->mode(25); # DEC private mode 25
my $on = $term->mode(4, 1); # ANSI mode 4
Whether a mode is set. Returns undef for a mode the terminal does not know, and croaks if the number is not between 0 and 32767.
active_screen
'primary' or 'alternate'. Full-screen programs such as editors and pagers normally switch to the alternate screen.
mouse_tracking
True if the program enabled any mouse reporting mode.
scrollback_rows
Number of rows in the scrollback history.
lib_version
my $version = Term::Ghostty->lib_version;
The version of the linked libghostty-vt.
on_pty_write
my $old = $term->on_pty_write(sub { ... });
$term->on_pty_write(undef);
my $cb = $term->on_pty_write;
Gets or replaces the callback; with an argument, returns the previous one. See "CALLBACKS".
on_title_changed
Like "on_pty_write", for the title callback.
on_bell
Like "on_pty_write", for the bell callback.
on_pwd_changed
Like "on_pty_write", for the working directory callback.
CALLBACKS
- on_pty_write($term, $bytes)
-
Bytes the terminal sends back to the program: answers to status queries, mode reports and so on. Write them to the pseudo-terminal.
$bytesis a byte string. - on_title_changed($term, $title)
-
The title was changed by OSC 0 or OSC 2.
- on_bell($term)
-
A BEL character (0x07) outside an escape sequence.
- on_pwd_changed($term, $url)
-
The working directory was reported by OSC 7, OSC 9;9 or OSC 1337 CurrentDir. See "pwd" for the format.
Callbacks run synchronously inside "feed", "write", "write_until_ground" and "resize". Inside a callback the terminal can be read, and callbacks can be replaced, but methods that change it (feed, write, write_until_ground, resize, reset, set_title, set_pwd) croak.
If a callback dies, the rest of the input is still processed, the remaining callbacks of that call are skipped, and the method rethrows the first error once the library has returned.
Use the terminal passed as the first argument instead of closing over the variable that holds it; a closure over that variable creates a reference cycle and the terminal is never freed.
QUERIES
With on_pty_write set, the terminal answers device attribute queries (primary as a VT220 with ANSI colour, CSI ? 62 ; 22 c, secondary and tertiary), device status and cursor position reports, mode and setting queries (DECRQM, DECRQSS), palette colour queries (OSC 4), XTVERSION, the Kitty keyboard query, window size queries (CSI 14 t, CSI 16 t, CSI 18 t; pixel sizes are 0 unless a cell size was given) and in-band resize reports. Default colour queries (OSC 10 and 11), clipboard reads (OSC 52), ENQ and the colour scheme query (CSI ? 996 n) are not answered.
ENCODING
"feed" takes bytes or characters as described above. "format" and its wrappers, "title" and "pwd" return character strings; malformed UTF-8 coming from the program is replaced by U+FFFD. on_pty_write receives bytes.
HTML OUTPUT
HTML output is a <div> with inline styles. Palette colours refer to the CSS variables --vt-palette-0 to --vt-palette-255, which the <style> block emitted by default defines on :root; pass palette => 0 to define them yourself. Text is HTML-escaped. Hyperlinks (OSC 8) become <a href>; links whose URL does not start with http://, https://, ftp://, mailto: or file:// are emitted without the href, so a program cannot plant javascript: links in the page.
THREADS
A terminal belongs to the thread that created it. New threads get an unusable copy; create a separate terminal in each thread. Terminals cannot be serialized or cloned with Storable.
EXAMPLES
The examples directory of the distribution has scripts that drive programs in a pseudo-terminal, convert ANSI output to HTML, replay asciinema recordings and more.
SEE ALSO
Alien::ghostty, Term::VTerm, Ghostty
AUTHOR
vividsnow
COPYRIGHT AND LICENSE
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
libghostty-vt, which is linked into this module, is copyright Mitchell Hashimoto and the Ghostty contributors and is distributed under the MIT license. It includes third-party code, such as simdutf, Highway and Wuffs, under their own permissive licenses; see its source for the texts.