# Terminal State Report (DECRQTSR, DECTSR, DECRSTS)

> Ask for most of the terminal's settable state in one compact report, and send it back later to restore it.

- **Sequence:** `CSI Ps $ u`
- **Defaults:** Ps = 0, no report
- **DEC STD 070:** [§5.13.2 Request Terminal State Report, p. 5-206](https://archive.org/details/bitsavers_decstandar0VideoSystemsReferenceManualDec91_74264381/page/n460/mode/1up)
- **VT510:** [DECRQTSR—Request Terminal State Report](https://vt100.net/docs/vt510-rm/DECRQTSR.html)

DECRQTSR asks the terminal for a *terminal state report*, DECTSR: one
device control string that holds most of what the host could have set.
DECRSTS sends such a report back to restore that state. All three belong
to the terminal state interrogation extension, levels 2 and above with the
extension and 3 and 4, and DEC STD 070 defines them on consecutive pages:

| Function | Sequence | Direction | DEC STD 070 | VT510 |
| --- | --- | --- | --- | --- |
| DECRQTSR | `CSI Ps $ u` | host to terminal | [p. 5-206](https://archive.org/details/bitsavers_decstandar0VideoSystemsReferenceManualDec91_74264381/page/n460/mode/1up) | [DECRQTSR](https://vt100.net/docs/vt510-rm/DECRQTSR.html) |
| DECTSR | `DCS 1 $ s D…D ST` | terminal to host | [p. 5-207](https://archive.org/details/bitsavers_decstandar0VideoSystemsReferenceManualDec91_74264381/page/n461/mode/1up) | [DECTSR—Terminal State Report—Terminal to Host](https://vt100.net/docs/vt510-rm/DECTSR.html) |
| DECRSTS | `DCS Ps $ p D…D ST` | host to terminal | [p. 5-208](https://archive.org/details/bitsavers_decstandar0VideoSystemsReferenceManualDec91_74264381/page/n462/mode/1up) | [DECRSTS—Restore Terminal State](https://vt100.net/docs/vt510-rm/DECRSTS.html) |

DECRQTSR's parameter chooses the report:

| `Ps` | Report |
| --- | --- |
| `0`, or left out | "ignored, no report sent" |
| `1` | a terminal state report, DECTSR |

"If the terminal does not recognize the type of DECTSR requested, the entire
command is ignored."

What is in a DECTSR is not something a host can rely on. DEC STD 070 says
"The format of the data is firmware revision dependent", and that it should
not be expected to stay the same "across firmware revisions or different
members of a terminal family". The data is a string of bytes ending in a
two-byte checksum; on the VT420 it is 110 bytes. It leaves out "the contents
of the logical display, DRCS, UDK definitions, and Macros". So there is no
case for what DECRQTSR 1 answers: the sources say only that it is a DECTSR,
not what is in it.

DECRSTS takes the same kind of data back. Its parameter names the format,
and `0` is "illegal, restore ignored". The terminal checks the checksum
first: "If the checksum fails, the entire sequence is ignored", and if a
value inside is invalid the terminal may skip the rest, "parsing until a ST
control is encountered", with "No error indication" returned. The data is
meant to be a report the terminal itself produced: "Software should not use
DECRSTS to restore a terminal to a saved state unless that state was
previously read from the terminal."

xterm implements none of the three. Its parse table sends `CSI $ u` back to
the ground state with nothing done
([`VTPrsTbl.c`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/VTPrsTbl.c#L3223)):

```c
CASE_GROUND_STATE,	/* vt420:DECRQTSR */
```

and its device control strings with `$` restore only DECRSPS, `DCS Ps $ t`,
so a `DCS Ps $ p` is dropped
([`misc.c`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/misc.c#L5310-L5349)).
A default xterm therefore ignores all three, and the cases follow it, as the
[sources](https://control-codes.page/sources/index.html.md) page explains. Each case checks something DEC STD 070
says is ignored as well, so the two agree on everything tested here.

## Not in libghostty-vt

libghostty-vt has no terminal state report. It does not recognize
`CSI $ u`, and its DCS handler in `dcs.zig` recognizes tmux control mode,
XTGETTCAP (`DCS + q`) and DECRQSS (`DCS $ q`) and drops every other device
control string, DECRSTS included. The cases pass because it ignores
them, as a default xterm does.

## Validation

### DECRQTSR-1: No report asked for

Input, one step per line:

```text
\e[$u     # Ps left out
\e[0$u
```

Expected screen:

```text
|_____|
reply none
```

### DECRQTSR-2: An unknown report

Input, one step per line:

```text
\e[3$u    # no such report type
X
```

Expected screen:

```text
|X____|
cursor 1,2
reply none
```

### DECRQTSR-3: A restore is not displayed

Input, one step per line:

```text
\eP0$p@@@@@@\e\\   # DECRSTS with Ps 0: illegal, ignored
\eP1$pABCD@@\e\\   # and data the terminal never sent
X
```

Expected screen:

```text
|X____|
cursor 1,2
reply none
```

---

This is the Markdown version of <https://control-codes.page/csi/decrqtsr/>. On that page every validation case runs live in libghostty-vt, the terminal emulation core of Ghostty, compiled to WebAssembly.

The validation cases are written in the notation described in <https://control-codes.page/notation/index.html.md>.
