# Select Conformance Level (DECSCL)

> Make the terminal behave as an earlier level of DEC terminal, with a soft reset.

- **Sequence:** `CSI Pl ; Pc " p`
- **DEC STD 070:** [§4, ch. 5 Select Conformance Level, p. 22](https://archive.org/details/bitsavers_decstandar0VideoSystemsReferenceManualDec91_74264381/page/n225/mode/1up)
- **VT220:** [§4.3 Compatibility Level (DECSCL)](https://vt100.net/docs/vt220-rm/chapter4.html#S4.3)
- **VT510:** [DECSCL—Select Conformance Level](https://vt100.net/docs/vt510-rm/DECSCL.html)

Set the level the terminal operates at, so that it behaves like an older
model for software written for one. `Pl` is the level as [DA](https://control-codes.page/csi/da/index.html.md)
reports it: `61` for level 1 (a VT100), `62` for level 2 (a VT200), `63`
and `64` for levels 3 and 4. For levels 2 and up, `Pc` chooses the controls
the terminal sends: `1` for 7-bit, `ESC [` and the like, and `0` or `2` for
the 8-bit C1 bytes.

Changing level also performs a soft reset, like [DECSTR](https://control-codes.page/csi/decstr/index.html.md):
DEC STD 070 says selecting a level "causes a 'soft reset' of the terminal to
be performed", and that a level the terminal does not support is ignored.
xterm's source notes that the VT300, VT420 and VT520 manuals call it a full
reset instead, and does the soft reset
([`CASE_DECSCL`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/charproc.c#L5088-L5133)).
xterm also refuses a level higher than its own terminal's, so a VT420 cannot
be set to level 5, and refuses any `Pl` below `61`.

The level then decides what the terminal accepts. In xterm, control
sequences with a `$` intermediate, DECRQM among them, need level 3
([`CASE_CSI_DOLLAR_STATE`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/charproc.c#L5608-L5615)),
and the left and right margins need level 4
([`srm_DECLRMM`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/charproc.c#L7783-L7790)).
esctest2's `decscl.py` tests both.

libghostty-vt does not implement DECSCL: its `p` dispatch in `stream.zig`
handles only DECRQM, and logs any other intermediate as unimplemented. It
keeps its one level, so it answers DECRQM and honors margins whatever is
asked for, and it does not reset. The cases that depend on the level changing
are known differences from xterm, a VT420 by default.

## Validation

### DECSCL-1: Level 2 has no DECRQM

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

Input, one step per line:

```text
\e[62;1"p # level 2, 7-bit controls
\e[4$p    # DECRQM for insert mode
```

Expected screen:

```text
|__________|
reply none
```

### DECSCL-2: Level 3 has no left and right margins

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

Input, one step per line:

```text
\e[63;1"p # level 3
\e[?69h   # allow left and right margins
\e[5;6s   # margins at columns 5 and 6
\e[1;5H
abc
```

Expected screen:

```text
|____abc___|
|__________|
cursor 1,8
```

### DECSCL-3: Level 4 has them

Input, one step per line:

```text
\e[64;1"p # level 4
\e[?69h   # allow left and right margins
\e[5;6s   # margins at columns 5 and 6
\e[1;5H
abc
```

Expected screen:

```text
|____ab____|
|____c_____|
cursor 2,6
```

### DECSCL-4: Changing level is a soft reset

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

Input, one step per line:

```text
\e[4h     # insert mode
\e[64;1"p # level 4
\e[4$p    # DECRQM for insert mode
```

Expected screen:

```text
|__________|
reply \e[4;2$y
```

### DECSCL-5: A level above the terminal's own is refused

Input, one step per line:

```text
\e[4h     # insert mode
\e[65;1"p # level 5, more than a VT420
\e[4$p    # DECRQM for insert mode
```

Expected screen:

```text
|__________|
reply \e[4;1$y
```

---

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