^[control-codes
live in libghostty-vt

C0 control characters

SO, SI Shift Out and Shift In

View as Markdown

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

SO Shift Out

SO
ECMA-48
§8.3.126 SO – Shift-Out, p. 65
DEC STD 070
§3.8.3.1 Shift Out, p. 3-74
VT220
§4.4.3 Invoking Character Sets with Locking Shifts
VT510
4.2 Control Characters

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 and DEC STD 070 §3.8.3.1, p. 3-73. 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 and the VT510 manual’s SCS page. 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).

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.

Support

TerminalVersionSupportNotes
VT220manual, 2nd ed., 1984Yes§4.4.3 Invoking Character Sets with Locking Shifts
VT510manual, 1st ed., 1993YesTable 4–1
xtermpatch 412, xterm-411aYesSO and SI
libghostty-vt0f171f6YesSO and SI
kitty0.49.1, run in a VMYespasses the 3 cases that show it working
foot1.28.0, run in a VMYespasses the 3 cases that show it working
pyte0.8.2, run as a libraryNofails the 3 cases that show it working
xterm.js headless6.0.0, run as a libraryYespasses the 3 cases that show it working
alacritty_terminal0.26.0, run as a libraryYespasses the 3 cases that show it working
rxvt-unicode9.31, run in a VMYespasses the 3 cases that show it working
VTE0.84.1, run as a libraryYespasses the 3 cases that show it working

Validation

SO-1: Out to G1, and back

\e)0      # G1 is DEC Special Graphics
\x0e      # SO
qxlkjm
\x0f      # SI
q
|─│┌┐┘└q___|

SO-2: The shift lasts across lines

\e)0      # G1 is DEC Special Graphics
\x0e      # SO
q\r\nq
\x0f      # SI
q
|─_________|
|─q________|

SO-3: Designating the set in use

\e(0      # G0, which is in use, is DEC Special Graphics
qx
\e(B      # and back to ASCII
qx
|─│qx______|
Every example on these pages runs in your browser, in libghostty-vt compiled to WebAssembly.