^[control-codes live in libghostty-vt

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.

  • ESC is the byte 1B.
  • CSI is 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.
  • OSC is the Operating System Command introducer, ESC ].
  • ST is the String Terminator, ESC \. Most terminals also accept BEL (07) in its place.
  • A dashed box is a parameter. Pn is a number, Ps is a number that selects one of a fixed set of behaviors, and Pt is 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.

EscapeByte
\e1B, ESC
\a \b \t \n \v \f \r07 08 09 0A 0B 0C 0D
\s20, a space
\xNNthe byte NN in hexadecimal
\NNNthe 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:

LineChecks
cursor R,Cthe cursor is at row R, column C, counting from 1
pending-wrap yesthe cursor is in the last column with a wrap pending (or no)
cursor-visible nothe cursor is hidden (or yes, shown)
title "text"the window title, as a JSON string
progress textthe progress reports sent with OSC 9 ; 4, in order and separated by commas, such as set 50, remove; progress none for none
pointer namethe 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 texteverything the terminal sent back to the host, in the input’s escape notation, or reply none for nothing
bell Nhow 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.