^[control-codes live in libghostty-vt

Escape sequences

DECAUPSS Assign User-Preference Supplemental Set

Choose which supplemental character set is the user's preferred one, or ask which it is.

DCS Ps ! u Pt ST
DEC STD 070
§5.8.2 Assign User-Preference Supplemental Set, p. 5-123
VT510
DECAUPSS—Assigning User-Preferred Supplemental Sets

A DEC terminal keeps one supplemental character set as the user-preference supplemental set, the UPSS: the set of accented letters and symbols its user chose in Set-Up. DEC STD 070 gives it three jobs. It is the default supplemental set, designated into G2 by a soft reset; it decides which supplemental characters the keyboard can produce; and it lets a program designate “whatever the user prefers” without knowing which set that is.

DCS Ps ! u Pt ST (DECAUPSS) assigns it, and CSI & u (DECRQUPSS) asks which set it is, the terminal answering with a DECAUPSS string of its own. DEC STD 070 allows two values:

PsPtSet
0%5DEC Supplemental, 94 characters
1AISO Latin-1 supplemental, 96 characters

Ps says whether the set has 94 or 96 characters, and Pt is the same designator that would select the set with SCS. DECRQUPSS is DEC STD 070 §5.8.2, p. 5-125 and DECRQUPSS in the VT510 manual. DEC STD 070 has both answer and request sent with the 8-bit DCS and ST, 90 and 9C; xterm sends ESC P and ESC \.

The final byte < designates the UPSS itself: DEC STD 070’s example is ESC * <, which “designates the UPSS to G2” (p. 5-117). At the VT320 and VT420 levels, xterm turns < into DEC Supplemental if that is the UPSS and into ISO Latin-1 supplemental otherwise (HandleUPSS).

What xterm does

xterm implements both from the VT320 level up, and it is a VT420 by default (DFT_DECID). What it answers depends on whether it is decoding its input as UTF-8. libghostty-vt always does (see CSI), so the cases here compare it with xterm in UTF-8 mode, in which:

  • the UPSS starts out as ASCII, because neither supplemental set can work alongside UTF-8 decoding, as the comment in resetCharsets explains, so DECRQUPSS answers \eP0!uB\e\\ (CASE_DECRQUPSS);
  • DECAUPSS is ignored (misc.c).

Outside UTF-8 mode the UPSS starts out as ISO Latin-1, because xterm’s preferLatin1 resource is true by default (charproc.c, ptyx.h), and DECAUPSS accepts DEC STD 070’s two values and a few more that real VT520s were found to take (decode_upss).

xterm’s DECRQUPSS also has a bug: unlike the requests around it, it does not return the parser to its ground state afterwards. The parser is left in the table for CSI & sequences (VTPrsTbl.c), in which a printable character just returns to the ground state, so the first character printed after the request is lost.

libghostty-vt implements neither. Its CSI u dispatch in stream.zig has no case for a & intermediate, and its DCS hook in dcs.zig knows only + and $ intermediates, so it does not answer DECRQUPSS and drops a DECAUPSS string unread.

Validation

DECAUPSS-1: Asking for the UPSS

\e[&u     # DECRQUPSS
|______|
reply \eP0!uB\e\\

DECAUPSS-2: Assigning it is ignored in UTF-8 mode

\eP1!uA\e\\  # DECAUPSS: ISO Latin-1 supplemental
\e[&u
|______|
reply \eP0!uB\e\\

DECAUPSS-3: The character after the request is lost

\e[&u
AB        # xterm drops the A
|B_____|
cursor 1,2
reply \eP0!uB\e\\
Every example on these pages runs in your browser, in libghostty-vt compiled to WebAssembly.