# Save DEC Private Mode Values (XTSAVE)

> Remember the state of some private modes, to put back later.

- **Sequence:** `CSI ? Pm s`
- **xterm:** [Functions using CSI](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html)

`CSI ? Pm s` saves the state of each private mode it names, and
[XTRESTORE](https://control-codes.page/csi/xtrestore/index.html.md), `CSI ? Pm r`, puts it back. A program that
needs a mode for a while, say autowrap off while it draws a status line, can
save the mode, change it, and restore it afterwards without having to know
how it was set to begin with. It changes no mode itself.

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](https://control-codes.page/modes/index.html.md) numbers, the same as
[DECSET](https://control-codes.page/csi/decset/index.html.md)'s, and the `?` is what keeps it apart from another
sequence with the same final byte. Without the `?`, `CSI s` is [DECSLRM](https://control-codes.page/csi/decslrm/index.html.md), or saves the
cursor.

xterm's own description calls it a one-level cache, like
[DECSC](https://control-codes.page/esc/decsc/index.html.md)'s: each mode has one saved state, and saving it again
replaces it. Unlike DECSC, the modes are saved one by one, and only the ones
named. xterm saves each in turn in
[`savemodes`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/charproc.c#L8052-L8400), which knows nearly every private
mode it has; a number it does not know is skipped. libghostty-vt keeps one
saved state per mode the same way.

## Validation

### XTSAVE-1: Save, change, and restore

Input, one step per line:

```text
\e[?7s     # save autowrap, which is on
\e[?7l
\e[?7r
ABCDEFG
```

Expected screen:

```text
|ABCDE|
|FG___|
cursor 2,3
```

### XTSAVE-2: Saving changes nothing

Input, one step per line:

```text
\e[?7l
\e[?7s
ABCDEFG
```

Expected screen:

```text
|ABCDG|
|_____|
cursor 1,5
```

### XTSAVE-3: Several modes in one sequence

Input, one step per line:

```text
\e[?7;25s  # autowrap and the cursor
\e[?7;25l
\e[?7;25r
\e[?7$p
\e[?25$p
```

Expected screen:

```text
|_____|
reply \e[?7;1$y\e[?25;1$y
```

### XTSAVE-4: A second save replaces the first

Input, one step per line:

```text
\e[?7s     # on
\e[?7l
\e[?7s     # off, in place of on
\e[?7h
\e[?7r
ABCDEFG
```

Expected screen:

```text
|ABCDG|
|_____|
cursor 1,5
```

---

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