跳到主要内容
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

说明

前缀 ?sr 置入 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
支持

相关序列