DECSET ?2026 — 同步更新模式
在帧结束信号到来前缓冲屏幕更新 —— 全屏重绘时消除闪烁。
字节形式
涵盖所有常见的字符串字面量写法,方便正反查找。
\\x1b[
\x1b[?2026h (begin frame) \x1b[?2026l (end frame)\\033[
\033[?2026h / \033[?2026l\\e[
\e[?2026h / \e[?2026lESC [
ESC [ ? 2 0 2 6 h / lhex
1b 5b 3f 32 30 32 36 68 / 6c说明
最早由 iTerm2 + contour 提案,如今 kitty、wezterm、foot、ghostty、Windows Terminal、mintty、alacritty(1.7+)以及 tmux(直通)均已采纳。把整屏重绘包裹在 \x1b[?2026h(开始同步更新)与 \x1b[?2026l(结束)之间,终端会暂停渲染直到收到 l,然后一次性绘制最终状态 —— 消除 neovim、helix、tui-rs、ratatui 等程序在慢速 PTY(尤其 SSH)下的半帧抖动。不识别 ?2026 的终端按字节顺序绘制,因此可放心成对发送。需要严格检测的程序可用 DECRQM 查询 \x1b[?2026$p 并解析回报。建议单帧内 ≤ 100 ms —— 超时后终端会自动中止同步状态,避免屏幕卡死。
规范出处: Synchronized Output Mode (contour spec) / Mode 2026
示例
printf '\033[?2026h' # begin frame\n# … emit the full repaint here …\nprintf '\033[?2026l' # end frame -> painted atomicallyimport sys\nsys.stdout.write('\x1b[?2026h'); redraw(); sys.stdout.write('\x1b[?2026l')fmt.Print("\x1b[?2026h"); redraw(); fmt.Print("\x1b[?2026l")process.stdout.write('\x1b[?2026h'); redraw(); process.stdout.write('\x1b[?2026l')printf("\x1b[?2026h"); redraw(); printf("\x1b[?2026l");在哪里用到
实际会发出该序列的工具——把抽象字节锚定到你已经用过的命令上。
- Helix editorHelix 把每次整屏重绘包在 `\x1b[?2026h` … `\x1b[?2026l` 里 —— 终端把一帧缓冲后原子翻页,宽窗格布局滚动大文件时不再有撕裂带
- neovim (≥ 0.10) atomic redrawsnvim 用 DECRQM `\x1b[?2026$p` 探测;若返回 mode-2 / mode-3,每个 `redraw` 周期都包在 BSU / ESU 里 —— 调整大小、状态行更新、并排 `:diffupdate` 时收益明显
- Ghostty, kitty, alacritty (0.13+), WezTerm四款都声明支持 DECSET 2026 —— 终端把每个字节排队,直到 ESU 抵达才一次性提交整帧;不声明支持,Helix / nvim 降级为逐格重绘
- btop, btm, gtop dashboard TUIs高帧率资源监控(btop / btm)把内循环重绘包在 BSU / ESU 里 —— CPU / 内存柱不会更新到一半撕裂;不开同步时,滚动重绘慢的终端会看到旧柱与新柱之间的可见分界
- tmux refresh, zellij pane resize复用器在 resize 和 `refresh-client` 时把窗格重绘突发包在 BSU / ESU 里 —— 每个窗格原子落地;不开同步时拆分窗口会短暂出现半绘制的窗格并排
常见问题
针对这条序列,开发者真正会去搜索的问题的简短回答。
- DECSET ?2026(同步输出)到底解决什么问题?
- 解决全屏重绘时的撕裂。当 TUI 每帧重写所有单元格,终端可能在更新中途绘屏 —— 用户在一两帧里看到上半屏新内容、下半屏旧内容。把重绘包在
\x1b[?2026h…\x1b[?2026l之间,告诉终端缓冲单元格更新、整帧原子翻转 —— 思路与双缓冲的 SDL/OpenGL swap 相同。Helix、Neovim、Ghostty 自带 TUI 以及现代 TUI 框架在终端宣告支持时都会启用。 - 启用
?2026前怎样检测终端是否支持? - 用 DECRQM 查询:
\x1b[?2026$p。支持的终端回复\x1b[?2026;1$y(已置位)或\x1b[?2026;2$y(已复位但识别)。不识别的模式回\x1b[?2026;0$y或干脆不回 —— 都表示不要用。非阻塞读、50ms 超时;无回复就假定不支持。Kitty、ghostty、WezTerm、Mintty、foot、iTerm2(≥3.5)都支持;xterm、gnome-terminal、konsole、Linux 控制台暂不支持。
终端支持
- 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 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 不支持 | 不支持 | 不支持 | 支持 | 支持 | 不支持 | 支持 | 支持 | 支持 | 支持 | 部分 | 支持 | 支持 | 不支持 |