DECSTR 副作用 —— `\x1b[!p` 究竟重置哪些模式
DECSTR(软重置)会恢复到默认的每一个 DEC 模式 / 属性枚举参照 —— 哪些会被清、哪些保留、xterm / kitty / iTerm2 在哪里发生分歧。
字节形式
涵盖所有常见的字符串字面量写法,方便正反查找。
\x1b[!p\033[!p\e[!pESC [ ! p1b 5b 21 70说明
decstr-soft-reset 的伴生参照 —— 字节序列相同(\x1b[!p),扩展为 DEC VT510 RM §8.4.1 的完整副作用清单。问题是 「DECSTR 会不会把我的 X 弄丢?」 而非 「软重置怎么写?」 时看本页。
DECSTR 不会动:
- 屏幕内容(主屏 / 备用屏 —— 保留)
- 回滚缓冲(保留)
- 备用屏快照(保留)
- 窗口标题 / 图标名(OSC 0/2 设置的 —— 保留)
- G0..G3 字符集定义(定义保留;活动 GL/GR 指针被重置 —— 见下)
- 宏定义(DECDMAC 条目保留 —— 见 dcs-decdmac)
- 用户键(DECUDK 条目保留 —— 见 dcs-decudk)
- 光标位置(仍在原单元格)
DECSTR 会重置至以下默认值:
- IRM(插入 / 替换,\x1b[4h/l)→ 替换
- DECOM(原点模式,?6h/l —— 见 dec-origin-mode)→ 关(绝对)
- DECAWM(自动换行,?7h/l —— 见 dec-line-wrap)→ 开
- DECNRCM(国家替换字符集,?42h/l)→ 关
- DECNKM(数字 / 应用小键盘 —— 见 deckpam-deckpnm)→ 数字
- KAM(键盘动作,\x1b[2h/l)→ 解锁
- DECSCA(字符保护选择 —— 见 decsca)→ 全部无保护
- DECSCNM(反相屏幕,?5h/l —— 见 decscnm)→ 正常(关)
- DECTCEM(光标可见,?25h/l —— 见 cursor-visibility)→ 开(光标可见)
- DECCKM(光标键模式,?1h/l)→ 正常
- DECRLM(从右至左模式,?34h/l)→ 关
- DECSCUSR(光标形状 —— 见 dec-cursor-shape)→ 实现默认(通常为闪烁方块,\x1b[0 q)
- DECSTBM(上下边距 —— 见 decstbm)→ 全屏(1 .. 高)
- DECSLRM(左右边距 —— 见 decslrm)→ 全屏(1 .. 宽),仅 DECLRMM 开时
- SGR(所有字符属性:颜色、加粗、斜体等)→ 默认(\x1b[0m)
- DECSC 保存的光标栈 → 清空
- GL / GR 映射 → GL → G0,GR → G2(规范默认)
- 选择性擦除状态 → 关
厂商分歧:
- xterm、kitty、alacritty、wezterm、ghostty、konsole:与规范完全一致。
- iTerm2:不重置 DECSCUSR —— 光标形状跨 \x1b[!p 保留。如需顺带恢复形状,DECSTR 后显式发 \x1b[0 q。
- Windows Terminal:1.20 之前的构建不重置 DECSLRM。现代构建与规范一致。
- Linux console(内核 vt):旧内核把 DECSTR 当作 RIS-lite —— 屏幕和回滚也会清。别依赖回滚保留。
- macOS Terminal:静默忽略 DECSCA 重置(选择性擦除保护保留)。
- cmd.exe / ConPTY:部分实现;SGR + DECTCEM 会重置,其余多数忽略。
DECSTR vs RIS 何时选择:DECSTR 保留用户可见屏幕 + 回滚;RIS(见 ris-reset)一并清掉。「我刚退出一个状态不明的 TUI —— 优雅恢复又不丢上下文」用 DECSTR。「用户输 reset 因为终端卡死了」用 RIS(reset shell 命令通过 terminfo rs1 实际发的就是它)。
离场防御性模式: ``` 启动时: 通过 DECRQSS 快照在意的状态(SGR、光标形状、边距、鼠标模式) 退出(defer / 信号处理): 发 \x1b[!p # 软重置清除多数状态 发 \x1b[0 q # 强制光标形状(iTerm2 兜底) 发 \x1b[?1l\x1b> # 光标键 + 小键盘归位(额外保险) 发 \x1b[?25h # 光标可见(偏执 —— DECSTR 本来就会做) ```
规范出处: DEC VT510 RM §8.4.1 (DECSTR side-effect table) / xterm-ctlseqs
示例
# Soft reset — preserves screen + scrollback. Side-effects as listed above.\nprintf '\\033[!p'# Probe DECSCUSR after DECSTR to verify cursor-shape reset (catches iTerm2).\nimport sys\nsys.stdout.write('\\x1b[!p\\x1bP$q q\\x1b\\\\')\nsys.stdout.flush()// Defensive exit: soft reset + explicit cursor shape + visible cursor.\nfunc restoreTerminal() {\n fmt.Print(\"\\x1b[!p\") // DECSTR\n fmt.Print(\"\\x1b[0 q\") // cursor shape -> default (iTerm2)\n fmt.Print(\"\\x1b[?25h\") // cursor visible (paranoia)\n}// On Node TUI exit, leave terminal pristine for the user's shell.\nprocess.on('exit', () => {\n process.stdout.write('\\x1b[!p\\x1b[0 q\\x1b[?25h');\n});/* DECSTR keeps screen but you may want to also clear scroll-region\n * since DECSTBM resets to full-screen. */\nprintf(\"\\x1b[!p\");\nprintf(\"\\x1b[H\"); /* cursor home — DECSTR leaves it where it was */\nfflush(stdout);终端支持
- xterm
- 支持
- Linux console (fbcon)
- 部分
- macOS Terminal.app
- 部分
- iTerm2
- 部分
- Windows Terminal
- 部分
- cmd.exe / ConPTY
- 部分
- kitty
- 支持
- alacritty
- 支持
- WezTerm
- 支持
- Ghostty
- 支持
- GNOME Terminal
- 支持
- Konsole
- 支持
- tmux
- 支持
- GNU screen
- 支持
| xterm | Linux console (fbcon) | macOS Terminal.app | iTerm2 | Windows Terminal | cmd.exe / ConPTY | kitty | alacritty | WezTerm | Ghostty | GNOME Terminal | Konsole | tmux | GNU screen |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 支持 | 部分 | 部分 | 部分 | 部分 | 部分 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |