Notation
Syntax diagrams
Each sequence page opens with the sequence laid out byte by byte. The name of each piece is on top and the byte it stands for is underneath, in hexadecimal.
ESCis the byte1B.CSIis the Control Sequence Introducer,ESC [. ECMA-48 also defines a single-byte CSI,9B, but terminals that decode their input as UTF-8 do not accept it, so it is not shown.OSCis the Operating System Command introducer,ESC ].STis the String Terminator,ESC \. Most terminals also acceptBEL(07) in its place.- A dashed box is a parameter.
Pnis a number,Psis a number that selects one of a fixed set of behaviors, andPtis text. A parameter left out takes its default, and several parameters are separated by;.
Validation cases
A case is two blocks: the input, and the screen it should produce. A fresh terminal is made for every case, exactly as wide and as tall as the expected screen, and the input is written to it.
Input
One line of input is one step: the stepping controls under each case advance a line at a time. Leading and trailing spaces on a line are ignored, and anything after a # that follows a space is a comment, which is shown beside the step.
| Escape | Byte |
|---|---|
\e | 1B, ESC |
\a \b \t \n \v \f \r | 07 08 09 0A 0B 0C 0D |
\s | 20, a space |
\xNN | the byte NN in hexadecimal |
\NNN | the byte NNN in octal, so \033 is ESC |
\u{NNNN} | the code point U+NNNN, encoded as UTF-8 |
\\ \# | a backslash, a # |
Everything else is written as UTF-8. Note that \n is only a line feed: it moves the cursor down without returning it to the left margin, because that is what the byte does.
Expected screen
Each row of the screen is written between bars, |like this|, with _ for an empty cell. The number of rows and the width of the first row set the size of the terminal. After the rows can come any of these:
| Line | Checks |
|---|---|
cursor R,C | the cursor is at row R, column C, counting from 1 |
pending-wrap yes | the cursor is in the last column with a wrap pending (or no) |
cursor-visible no | the cursor is hidden (or yes, shown) |
title "text" | the window title, as a JSON string |
progress text | the progress reports sent with OSC 9 ; 4, in order and separated by commas, such as set 50, remove; progress none for none |
pointer name | the mouse pointer’s shape, set with OSC 22, by its CSS name, such as text or wait |
pwd "text" | the working directory last reported with OSC 7, as a JSON string; "" for none |
attr R,C words… | the style of the cell at row R, column C |
reply text | everything the terminal sent back to the host, in the input’s escape notation, or reply none for nothing |
bell N | how many times the bell rang |
The words an attr line takes are bold, italic, faint, blink, inverse, invisible, strikethrough, overline and underline (or underline=double, curly, dotted, dashed), each of which can be negated with a leading -; fg=N and bg=N for a palette color, fg=#rrggbb for a direct color and fg=default; link for a cell that is part of an OSC 8 hyperlink; semantic=prompt, semantic=input or semantic=output for what OSC 133 marked the cell as; and plain for a cell with no styling at all.
Replies
Some sequences make the terminal answer the host: a status report, its cursor position, what kind of terminal it is. The runner collects those answers, in order, from libghostty-vt’s callbacks, and a reply line checks all of them together. On a page, a case that checks a reply or the bell shows what was sent back as you step through it.
Some answers are the host’s to choose rather than libghostty-vt’s. For those the runner gives the answers Ghostty itself gives: Device Attributes reports a VT220 with ANSI color, \e[?62;22c for the primary attributes and \e[>1;10;0c for the secondary, and the answerback message ENQ asks for is empty, as Ghostty’s enquiry-response is by default. A size report, CSI 18 t, gives the case’s own size, as a default xterm would; the size of a cell in pixels is an arbitrary 6 by 13.
Colors are the host’s choice too, and for those the runner follows a default xterm, since the cases do: the terminal starts with xterm’s palette and its black text on white, with the cursor in the foreground color. That is what a color query such as OSC 4 or OSC 11 answers, and what fg=N resolves to. The screens on this site are still drawn in the page’s own colors wherever a cell has the default ones.
Known differences
A case that libghostty-vt is known not to pass is marked as a known difference. A case’s expectation follows what a default xterm does, bugs included, even where DEC STD 070 or ECMA-48 says otherwise. That includes ignoring a function a default xterm ignores, so a function libghostty-vt implements and xterm does not is a known difference too; the sources page says more. A known difference is still run on every page load, and its badge says whether the difference is still there; the page’s prose explains it.