^[control-codes
live in libghostty-vt

Control sequences

XTRESTORE Restore DEC Private Mode Values

View as Markdown

Put back private modes saved with XTSAVE.

CSI ? Pm r
xterm
Functions using CSI

CSI ? Pm r sets each private mode it names back to the state XTSAVE, CSI ? Pm s, saved for it. Restoring a mode is the same as setting or resetting it with DECSET or DECRST, side effects included: restoring origin mode moves the cursor home, as setting it does. The saved state stays where it is, so the same mode can be restored again.

Only xterm defines it: DEC’s terminals had nothing like it, and none of ECMA-48, DEC STD 070 or the VT220 and VT510 manuals mentions it. Its parameters are private mode numbers, the same as DECSET’s, and the ? is what keeps it apart from another sequence with the same final byte. Without the ?, CSI r is DECSTBM.

xterm restores each mode in turn in restoremodes and skips a number it does not know, and so does libghostty-vt. They part over a mode that was never saved. xterm keeps its saved states in a table that starts out zeroed (charproc.c, when the terminal is created), so restoring a mode it never saved resets it, whatever its default: restoring autowrap turns it off (charproc.c), and restoring mode 25 hides the cursor. Nothing but XTSAVE writes that table, so a reset, RIS, leaves what was saved in place. libghostty-vt starts its saved states at each mode’s default instead, so restoring an unsaved mode puts the default back, and RIS returns every saved state to the default. Those cases are known differences.

Support

TerminalVersionSupportNotes
VT220manual, 2nd ed., 1984Nonot in the manual
VT510manual, 1st ed., 1993Nonot in the manual
xtermpatch 412, xterm-411aYes
libghostty-vt0f171f6YesXTRESTORE-5 to XTRESTORE-7: an unsaved mode goes back to its default, and RIS clears what was saved
kitty0.49.1, run in a VMPartlyfails XTRESTORE-1, XTRESTORE-2, XTRESTORE-3 of the 4 cases that show it working
foot1.28.0, run in a VMYespasses the 4 cases that show it working
pyte0.8.2, run as a libraryNofails the 4 cases that show it working
xterm.js headless6.0.0, run as a libraryNofails the 4 cases that show it working
alacritty_terminal0.26.0, run as a libraryNofails the 4 cases that show it working
ConEmubuild 230724, its documentationNonot in ConEmu’s list, whose CSI s only saves the cursor; ANSI escape codes
rxvt-unicode9.31, run in a VMYespasses the 4 cases that show it working
VTE0.84.1, run as a libraryPartlyfails XTRESTORE-3 of the 4 cases that show it working

Validation

XTRESTORE-1: The saved state comes back

\e[?7l
\e[?7s     # off
\e[?7h
\e[?7r
ABCDEFG
|ABCDG|
|_____|
cursor 1,5

XTRESTORE-2: It can be restored again

\e[?7l
\e[?7s
\e[?7h
\e[?7r
\e[?7h
\e[?7r     # still off
ABCDEFG
|ABCDG|
|_____|
cursor 1,5

XTRESTORE-3: A mode that is not known does not stop the others

\e[?7s
\e[?7l
\e[?9999;7r
ABCDEFG
|ABCDE|
|FG___|
cursor 2,3

XTRESTORE-4: Restoring origin mode moves the cursor home

\e[?6s
\e[3;5H
\e[?6r
X
|X____|
|_____|
|_____|
cursor 1,2

XTRESTORE-5: A mode never saved is reset

\e[?7r     # autowrap was never saved
ABCDEFG
|ABCDG|
|_____|
cursor 1,5

XTRESTORE-6: The cursor too

\e[?25r
\e[?25$p
|_____|
reply \e[?25;2$y

XTRESTORE-7: A reset leaves what was saved

\e[?7l
\e[?7s
\ec        # RIS: autowrap on again
\e[?7r
ABCDEFG
|ABCDG|
|_____|
cursor 1,5
Every example on these pages runs in your browser, in libghostty-vt compiled to WebAssembly.