# Shift Out and Shift In (SO, SI)

> Switch the characters printed to the G1 set, and back to G0.

- **Sequence:** `SO`
- **ECMA-48:** [§8.3.126 SO – Shift-Out, p. 65](https://archive.org/details/ecma-48-5th-edition-june-1991/page/n78/mode/1up)
- **DEC STD 070:** [§3.8.3.1 Shift Out, p. 3-74](https://archive.org/details/bitsavers_decstandar0VideoSystemsReferenceManualDec91_74264381/page/n178/mode/1up)
- **VT510:** [4.2 Control Characters](https://vt100.net/docs/vt510-rm/chapter4.html#S4.2)

A terminal holds four graphic character sets at once, G0 to G3, and prints
from whichever of them is *invoked* into GL, the left half of the code table
(`21` to `7E`). SO invokes G1 into GL, and SI (`0F`) invokes G0 back. Both
are locking shifts: everything printed after SO comes from G1, across any
number of lines, until SI.

SI is
[ECMA-48 §8.3.119, p. 63](https://archive.org/details/ecma-48-5th-edition-june-1991/page/n76/mode/1up)
and [DEC STD 070 §3.8.3.1, p. 3-73](https://archive.org/details/bitsavers_decstandar0VideoSystemsReferenceManualDec91_74264381/page/n177/mode/1up).
ECMA-48 gives the two bytes other names in an 8-bit environment, LS1 and LS0,
and leaves what they do to ECMA-35.

A set is *designated* into G0 to G3 with an escape sequence: `ESC ( F`,
`ESC ) F`, `ESC * F` and `ESC + F` put the 94-character set with final byte
`F` into G0, G1, G2 and G3 respectively. This is SCS, in
[DEC STD 070 §5.8.2, p. 5-117](https://archive.org/details/bitsavers_decstandar0VideoSystemsReferenceManualDec91_74264381/page/n371/mode/1up)
and the VT510 manual's [SCS page](https://vt100.net/docs/vt510-rm/SCS.html).
`B` is ASCII, and `0` is DEC Special Graphics, the set of line-drawing
characters that full-screen programs draw boxes with: `q` becomes `─`, `x`
becomes `│`, and `l`, `k`, `j` and `m` become the corners `┌`, `┐`, `┘` and
`└`. Those are the Unicode characters xterm maps them to
([`map_DEC_Spec_Graphic`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/charsets.h#L175-L211)).

Designating a set into the slot already invoked changes what is printed from
then on, with no shift needed; DEC STD 070 says so in its notes on SCS.

The shifts change only what is printed next. Characters already on the
screen stay as they are.

## Validation

### SO-1: Out to G1, and back

Input, one step per line:

```text
\e)0      # G1 is DEC Special Graphics
\x0e      # SO
qxlkjm
\x0f      # SI
q
```

Expected screen:

```text
|─│┌┐┘└q___|
```

### SO-2: The shift lasts across lines

Input, one step per line:

```text
\e)0      # G1 is DEC Special Graphics
\x0e      # SO
q\r\nq
\x0f      # SI
q
```

Expected screen:

```text
|─_________|
|─q________|
```

### SO-3: Designating the set in use

Input, one step per line:

```text
\e(0      # G0, which is in use, is DEC Special Graphics
qx
\e(B      # and back to ASCII
qx
```

Expected screen:

```text
|─│qx______|
```

---

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