# User-Preference Supplemental Set (DECAUPSS, DECRQUPSS)

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

- **Sequence:** `DCS Ps ! u Pt ST`
- **DEC STD 070:** [§5.8.2 Assign User-Preference Supplemental Set, p. 5-123](https://archive.org/details/bitsavers_decstandar0VideoSystemsReferenceManualDec91_74264381/page/n377/mode/1up)
- **VT510:** [DECAUPSS—Assigning User-Preferred Supplemental Sets](https://vt100.net/docs/vt510-rm/DECAUPSS.html)

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:

| `Ps` | `Pt` | Set |
| --- | --- | --- |
| `0` | `%5` | DEC Supplemental, 94 characters |
| `1` | `A` | ISO 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](https://control-codes.page/c0/so/index.html.md). DECRQUPSS is
[DEC STD 070 §5.8.2, p. 5-125](https://archive.org/details/bitsavers_decstandar0VideoSystemsReferenceManualDec91_74264381/page/n379/mode/1up) and
[DECRQUPSS](https://vt100.net/docs/vt510-rm/DECRQUPSS.html) 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](https://archive.org/details/bitsavers_decstandar0VideoSystemsReferenceManualDec91_74264381/page/n371/mode/1up)). At the VT320 and VT420 levels, xterm turns
`<` into DEC Supplemental if that is the UPSS and into ISO Latin-1
supplemental otherwise
([`HandleUPSS`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/charsets.c#L62-L74)).

## What xterm does

xterm implements both from the VT320 level up, and it is a VT420 by default
([`DFT_DECID`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/ptyx.h#L398-L400)). What it answers depends on whether it
is decoding its input as UTF-8. libghostty-vt always does (see
[CSI](https://control-codes.page/esc/csi/index.html.md)), 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`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/charproc.c#L1240-L1276) explains, so DECRQUPSS
  answers `\eP0!uB\e\\` ([`CASE_DECRQUPSS`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/charproc.c#L5854-L5870));
- DECAUPSS is ignored ([`misc.c`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/misc.c#L5310-L5326)).

Outside UTF-8 mode the UPSS starts out as ISO Latin-1, because xterm's
`preferLatin1` resource is true by default
([`charproc.c`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/charproc.c#L460), [`ptyx.h`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/ptyx.h#L1138-L1140)),
and DECAUPSS accepts DEC STD 070's two values and a few more that real VT520s
were found to take ([`decode_upss`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/misc.c#L4809-L4871)).

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`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/VTPrsTbl.c#L2749-L2898)), 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

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

Input, one step per line:

```text
\e[&u     # DECRQUPSS
```

Expected screen:

```text
|______|
reply \eP0!uB\e\\
```

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

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

Input, one step per line:

```text
\eP1!uA\e\\  # DECAUPSS: ISO Latin-1 supplemental
\e[&u
```

Expected screen:

```text
|______|
reply \eP0!uB\e\\
```

### DECAUPSS-3: The character after the request is lost

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

Input, one step per line:

```text
\e[&u
AB        # xterm drops the A
```

Expected screen:

```text
|B_____|
cursor 1,2
reply \eP0!uB\e\\
```

---

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