# Control Representation Mode (CRM)

> Show control characters as graphic symbols instead of performing them.

- **Sequence:** `CSI 3 h`
- **ECMA-48:** [§7.2.2 CRM – Control Representation Mode, p. 22](https://archive.org/details/ecma-48-5th-edition-june-1991/page/n35/mode/1up)
- **VT220:** [§2.7 Display Controls Mode](https://vt100.net/docs/vt220-rm/chapter2.html#S2.7)
- **VT510:** [CRM—Show Control Character Mode](https://vt100.net/docs/vt510-rm/CRM.html)

Mode 3 turns the terminal into a display of what it receives. Set, control
functions are shown as graphic symbols rather than performed; reset, which is
the default, they are performed.

| State | ECMA-48 calls it | Meaning |
| --- | --- | --- |
| Reset, `CSI 3 l` | CONTROL | control functions are performed |
| Set, `CSI 3 h` | GRAPHIC | control functions, except RM, are shown as graphic characters |

RM is the exception so that `CSI 3 l` can still turn the mode off.

DEC terminals call it Show Control Character Mode. The VT510 manual describes [CRM](https://vt100.net/docs/vt510-rm/CRM.html)
with a special font for the controls: every control is shown, and only LF,
FF and VT are also performed, as a new line. The VT510 lets the host set
it with `CSI 3 h`. The VT220 did not: its manual
([§2.7](https://vt100.net/docs/vt220-rm/chapter2.html#S2.7)) calls it display
controls mode, selected only in Set-Up, and says no escape sequence turns it
on. DEC STD 070 does not list it among the modes a host can set either.

xterm has no such mode. [`ansi_modes`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/charproc.c#L7399-L7424) ignores `CSI 3 h`, and controls keep working
afterwards. [DECRQM](https://control-codes.page/csi/decrqm/index.html.md) reports it as reset, `2`, rather than as
permanently reset ([`do_ansi_rqm`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/misc.c#L5408-L5463)), which says it is a mode xterm knows. libghostty-vt
ignores `CSI 3 h` as well, but does not recognize the number, and answers `0`.
So the DECRQM cases are known differences, and the case showing that the
controls still work is not.

## Validation

### CRM-1: Reported as reset

*A known difference: libghostty-vt does not pass this case.*

Input, one step per line:

```text
\e[3$p
```

Expected screen:

```text
|_____|
reply \e[3;2$y
```

### CRM-2: Even after it is set

*A known difference: libghostty-vt does not pass this case.*

Input, one step per line:

```text
\e[3h
\e[3$p
```

Expected screen:

```text
|_____|
reply \e[3;2$y
```

### CRM-3: Controls are still performed

Input, one step per line:

```text
\e[3h    # ignored
AB
\r
C
```

Expected screen:

```text
|CB___|
cursor 1,2
```

---

This is the Markdown version of <https://control-codes.page/ansi/crm/>. 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>.
