跳到主要内容
ansicode

XTSAVE / XTRESTORE — 保存 / 恢复 DEC 私有模式(`CSI ? Pm s` / `CSI ? Pm r`)

把一个或多个 DEC 私有模式状态压栈,稍后恢复 —— tmux / screen / fzf 用以安全地切换鼠标 / 备用屏 / 粘贴模式而不破坏用户设置的基础机制。

字节形式

涵盖所有常见的字符串字面量写法,方便正反查找。

\\x1b[\x1b[?<Pm>s (save) \x1b[?<Pm>r (restore)
\\033[\033[?1000s / \033[?1000r
\\e[\e[?1000s / \e[?1000r
ESC [ESC [ ? Pm s / ESC [ ? Pm r
hex1b 5b 3f ... 73 / 1b 5b 3f ... 72

说明

前缀 `?` 把 `s` 和 `r` 置入 **DEC 私有模式**命名空间(无前缀时 `CSI Ps ; Ps s` 为 DECSLRM —— 见 `decslrm` —— 而 `CSI Ps ; Ps r` 为 DECSTBM —— 见 `decstbm`)。带前缀后,`Pm` 为一个或多个分号分隔的 DEC 私有模式号(即 `CSI ? Pm h/l` 用来开关它们的同一组数字)。 - **XTSAVE**(`\x1b[?<Pm>s`)—— 把所列各模式的*当前*状态压入终端内部的逐模式栈。栈深通常逐模式 1 层深(第二次 XTSAVE 覆盖第一次);xterm 等少数实现维持任意深度的真栈。 - **XTRESTORE**(`\x1b[?<Pm>r`)—— 弹出并应用每个所列模式的已保存状态。若某模式从未保存过,对它而言 XTRESTORE 为空操作。 - 一次多模式:`\x1b[?1000;1002;1006;1049s` 一次保存鼠标 + 备用屏的四个模式;对称的 `\x1b[?1000;1002;1006;1049r` 一次恢复。 **为何存在** —— tmux、GNU screen、fzf、atuin、neovim 的 `:terminal`、lazygit 等交互工具需要临时改变鼠标追踪、备用屏、括号粘贴、焦点事件等,又不能在崩溃或用户切后台时给用户留下被破坏的设置。XTSAVE / XTRESTORE 是*非破坏性*的方式 —— 捕获用户偏好、切换到工具偏好、退出时无论用户原本怎样都能回滚。 **常用保存 / 恢复集合**(「tmux 鼠标集」):`?1000`(X10 鼠标)、`?1002`(cell motion 鼠标)、`?1003`(all-motion 鼠标)、`?1006`(SGR 鼠标编码)、`?1015`(urxvt 鼠标编码)、`?1049`(带光标保存的备用屏)。括号粘贴加 `?2004`;焦点事件 `?1004`。 **与 `?1049` 的关系** —— `\x1b[?1049h/l` 本身是*复合*序列,等效组合了 `?1047`(备用屏)+ `?1048`(光标保存)+ 进入时隐式保存 / 退出时恢复备用屏内容。除此之外,显式 XTSAVE / XTRESTORE 才是常规手段。不要再用 XTSAVE / XTRESTORE 包裹 `?1049` —— 它已自带往返。 **注意** —— xterm / iTerm2 / Kitty / WezTerm / Ghostty / Alacritty / Konsole / Windows Terminal 均实现;Linux console 仅部分实现常见模式;cmd.exe 不实现。栈深各异 —— 按 1 估,不要嵌套保存。macOS Terminal 实现最不齐,若以它为目标需专门测试。

规范出处: xterm-ctlseqs (XTSAVE / XTRESTORE — CSI ? Pm s / r)

参数

Pm一个或多个分号分隔的 DEC 私有模式号(如 `1000;1002;1006;1049`)。与 `CSI ? Pm h`(开启)/ `CSI ? Pm l`(关闭)使用的数字相同。

示例

bash
# Wrap an interactive subshell so mouse + alt-screen prefs survive it.\nprintf '\033[?1000;1002;1006;1049s'   # save\nprintf '\033[?1000l\033[?1049h'      # enter alt-screen, mouse off\nbash --noprofile --norc\nprintf '\033[?1049l'                  # leave alt-screen\nprintf '\033[?1000;1002;1006;1049r'   # restore user's modes
python
import sys\nMODES = '1000;1002;1006;1049'\nsys.stdout.write(f'\x1b[?{MODES}s')   # save\ntry:\n    sys.stdout.write('\x1b[?1000h')   # enable mouse for our app\n    run_app()\nfinally:\n    sys.stdout.write(f'\x1b[?{MODES}r')   # restore
go
// Defer-based save/restore wrapper for a TUI's mouse + altscreen setup.\nmodes := \"1000;1002;1006;1049\"\nfmt.Printf(\"\\x1b[?%ss\", modes)\ndefer fmt.Printf(\"\\x1b[?%sr\", modes)\nfmt.Print(\"\\x1b[?1049h\\x1b[?1000;1002;1006h\")   // enter alt-screen + cell-motion + SGR\nrunTUI()
javascript
// Node TUI — save on SIGINT/exit so user's mouse prefs always come back.\nconst modes = '1000;1002;1006;1049';\nprocess.stdout.write(`\\x1b[?${modes}s`);\nprocess.on('exit', () => process.stdout.write(`\\x1b[?${modes}r`));\nprocess.on('SIGINT', () => process.exit(130));
c
/* Save -> enter alt-screen + mouse -> restore on signal. */\nstatic const char *MODES = \"1000;1002;1006;1049\";\nprintf(\"\\x1b[?%ss\", MODES);\nsignal(SIGINT, on_exit_restore);\nprintf(\"\\x1b[?1049h\\x1b[?1000;1002;1006h\");\nrun_tui();\nprintf(\"\\x1b[?%sr\", MODES);

终端支持

xterm
支持
Linux console (fbcon)
部分
macOS Terminal.app
部分
iTerm2
支持
Windows Terminal
支持
cmd.exe / ConPTY
不支持
kitty
支持
alacritty
支持
WezTerm
支持
Ghostty
支持
GNOME Terminal
支持
Konsole
支持
tmux
不支持
GNU screen
不支持

相关序列