DECRQTSR / DECRSTS — Request / Restore Terminal State Report
Save (`CSI Ps$u` → DCS reply) and restore (`DCS Ps$p…ST`) the whole DEC terminal state — the terminal-wide complement to `dcs-decrsps`' presentation-state-only scope.
Byte forms
Every common string-literal form so you can paste-and-search either direction.
\x1b[Ps$u request \x1bP<Ps>$p<body>\x1b\\ restore\033[Ps$u request \033P<Ps>$p<body>\033\\ restore\e[Ps$u request \eP<Ps>$p<body>\e\\ restoreESC [ <Ps> $ u / ESC P <Ps> $ p <body> ESC \\1b 5b … 24 75 / 1b 50 <Ps> 24 70 <body> 1b 5cDescription
**DECRQTSR** (*Request Terminal State Report*, `\x1b[<Ps>$u`) and its inverse **DECRSTS** (*Restore Terminal State*, `\x1bP<Ps>$p<body>\x1b\\`) bracket the DEC mechanism for snapshotting an *entire terminal*'s mutable state into an opaque blob and faithfully restoring it later. They are the **terminal-wide** counterpart to `dcs-decrsps` / `dcs-decrqss`, which only carry the *presentation* slice (cursor, SGR, charset, origin, tab stops). **Request** — `\x1b[<Ps>$u`. `Ps=1` (the only universally-supported value) selects DEC terminal-state. Some VT-series docs reserve `Ps=2` for color-table state, but no shipping emulator implements `Ps=2` distinctly from `Ps=1` — treat `1` as the only portable selector. **Reply (DECTSR)** — `\x1bP<Ps>$s<body>\x1b\\`. The `$s` intermediate-final distinguishes the DECTSR reply from the DECRSTS *restore* shape (`$p`) and from DECRPSS (`$r`). The `<body>` is **opaque to the host** — it's a serialised DEC-private snapshot of: tab stops, character set state (G0/G1/G2/G3 designators + GL/GR + UPSS), all mode states (DECCKM / DECANM / DECCOLM / DECSCLM / DECSCNM / DECOM / DECAWM / DECARM / DECTCEM / DECNRCM / DECSCA / DECNKM / DECSCUSR / DECSDM / DECSLRM), printer state, keyboard-mode state, current SGR pen, cursor position + save stack, and protected-area state. Hosts **must not parse** the body — semantics are reserved to the originating terminal. **Restore** — `\x1bP<Ps>$p<body>\x1b\\`. Pass the same `<body>` back verbatim. The terminal validates that `<Ps>` matches the saved blob's `<Ps>` (cross-Ps restore is rejected silently with `\x1bP0$r\x1b\\` on emulators that reply, or simple no-op otherwise). Cross-terminal restore (saving on xterm, restoring on Konsole) is **not portable** — the body format is DEC-implementation-defined and each emulator has its own encoding. **Round-trip pattern** (TUI takeover + restore): ``` startup: write '\x1b[1$u' # DECRQTSR Ps=1 read DCS until ST # reply '\x1bP1$s<body>\x1b\\' save body exit: write '\x1bP1$p' + body + '\x1b\\' ``` The modern reality: most TUIs use **alt-screen** (`\x1b[?1049h`/`l`) + DECSC/DECRC for cursor/SGR. DECRQTSR/DECRSTS is the **terminal-wide** option only when alt-screen is unavailable (some BBS / serial-multiplexer paths) or when you need to round-trip modes that DECSTR doesn't touch (NRCS, UPSS, DECSCA). **Edge cases** - Reply uses `\x1b\\` (ST as ESC + backslash) by default; xterm in 8-bit C1 mode (`decscl-compat-level`) uses single-byte `\x9c` — be prepared to terminate on either. - Body bytes can include `\x1b` followed by **anything except `\\`** (DEC encodes embedded controls via DECDLD-style hex escapes); a naive 'split on ESC' parser will mis-frame — read until ST seen at packet boundary, not first ESC. - Some emulators (Linux console) reply with an empty body — restore is a silent no-op. - DECSTR (soft reset) does not clear an in-flight DECTSR snapshot held by the host, only the live terminal state. **Coverage** — **xterm** = full (reference; body length ~100-200 bytes typical). **mlterm** = full. **WezTerm** = partial (replies with a minimal body, restore accepts but only restores SGR + cursor + tabs — the modes DECSTR would reset get re-applied, the rest silently dropped). **Konsole** + **gnome-terminal** = partial (reply lacks UPSS / DECSCA fields, restore likewise truncated). **Kitty** + **iTerm2** + **Alacritty** + **Ghostty** + **Windows Terminal** + **cmd / ConPTY** + **macOS Terminal** + **Linux console** = no-op (no reply at all — prefer `alt-screen` + `cursor-save-restore` + `dcs-decrqss` for round-trip on these).
Spec citation: DEC VT510 RM (DECRQTSR / DECTSR / DECRSTS) / xterm-ctlseqs (CSI Ps $ u)
Parameters
| Ps = 1 | DEC terminal state. The only universally-supported value. |
| Ps = 2 | Reserved (color tables in some specs); no shipping emulator distinguishes from Ps=1. |
| Reply $s vs Restore $p | DCS intermediate-final `$s` = report (terminal → host); `$p` = restore (host → terminal). Don't swap. |
| <body> | Opaque DEC-private serialisation. Round-trip verbatim. Format varies per emulator — not cross-terminal portable. |
Examples
# Capture full terminal state, then restore on exit (xterm).\nprintf '\\033[1$u'\nIFS= read -rs -d '\\\\' -t 0.2 snapshot </dev/tty 2>/dev/null\n# ... session runs, mutates modes ...\n# Restore: re-emit the body in DECRSTS shape.\nbody=\"${snapshot#*\\\$s}\"\nbody=\"${body%\\\\}\"\nprintf '\\033P1$p%s\\033\\\\' \"$body\"import sys, re\n# Save snapshot, then later push it back.\nsys.stdout.write('\\x1b[1$u'); sys.stdout.flush()\nreply = sys.stdin.buffer.read1(4096)\nm = re.search(rb'\\x1bP1\\$s(.*?)\\x1b\\\\', reply, re.DOTALL)\nbody = m.group(1) if m else b''\n# ... TUI session ...\nsys.stdout.flush()\nsys.stdout.buffer.write(b'\\x1bP1$p' + body + b'\\x1b\\\\')// Skeleton: probe, read until ST, persist body for the duration of the run.\nfmt.Print(\"\\x1b[1$u\")\nvar buf [4096]byte\nn, _ := os.Stdin.Read(buf[:])\n// Match \\x1bP1$s<body>\\x1b\\\\.\nbody := extractDECTSR(buf[:n])\n// ...\nfmt.Printf(\"\\x1bP1$p%s\\x1b\\\\\", body)// Snapshot at startup, restore on exit handler.\nprocess.stdout.write('\\x1b[1$u');\nlet snapshot = '';\nprocess.stdin.once('data', (buf) => {\n const m = /\\x1bP1\\$s(.*?)\\x1b\\\\/s.exec(buf.toString('binary'));\n if (m) snapshot = m[1];\n});\nprocess.on('exit', () => {\n if (snapshot) process.stdout.write('\\x1bP1$p' + snapshot + '\\x1b\\\\');\n});/* Skeleton: snapshot at TUI entry, restore at exit. */\nfputs(\"\\x1b[1$u\", stdout); fflush(stdout);\n/* read until ST seen at packet boundary, store body bytes opaquely. */\n/* on exit: fputs(\"\\x1bP1$p\", stdout); fwrite(body, 1, body_len, stdout); fputs(\"\\x1b\\\\\", stdout); */Terminal support
- xterm
- yes
- Linux console (fbcon)
- no
- macOS Terminal.app
- no
- iTerm2
- no
- Windows Terminal
- no
- cmd.exe / ConPTY
- no
- kitty
- no
- alacritty
- no
- WezTerm
- partial
- Ghostty
- no
- GNOME Terminal
- partial
- Konsole
- partial
- tmux
- no
- GNU screen
- no
| xterm | Linux console (fbcon) | macOS Terminal.app | iTerm2 | Windows Terminal | cmd.exe / ConPTY | kitty | alacritty | WezTerm | Ghostty | GNOME Terminal | Konsole | tmux | GNU screen |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| yes | no | no | no | no | no | no | no | partial | no | partial | partial | no | no |