跳到主要内容
ansicode

DECTABSR —— 制表位报告(`CSI 2 $ w`)

让终端以 DCS 报告形式输出当前水平制表位。补全往返链:HTS(`esc-hts`)设置、TBC(`csi-tbc`)清除、DECTABSR 查询当前集合。

字节形式

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

\\x1b[\x1b[2$w
\\033[\033[2$w
\\e[\e[2$w
ESC [ESC [ 2 $ w
hex1b 5b 32 24 77

说明

DECTABSR —— *制表位报告* —— DECRQPSR(请求陈现状态报告)的一种,请终端以 DCS 形式列出当前水平制表位。它是制表位往返链的第三只脚: - 在当前列**设置**制表位:`\x1bH`(HTS,见 `esc-hts`)。 - **清除**:`\x1b[g`(当前列)/ `\x1b[3g`(全部)(TBC,见 `csi-tbc`)。 - **查询**当前集合:`\x1b[2$w`(DECTABSR —— 本条目)。 **请求形态**:`\x1b[2$w`(`2` 是 Ps 选择子 —— `1` 是 DECCIR 光标信息报告、`2` 是 DECTABSR)。`$` 中间字节 + `w` 末字节同 DECRQPSR 约定。 **回复形态(DECRPTAB)**:`\x1bP2$u<col1>/<col2>/…/<colN>\x1b\\` —— DCS 帧,体为以斜杠分隔的当前制表位列号(1 起算)。示例(xterm 80 列默认 8 列制表): ``` \x1bP2$u9/17/25/33/41/49/57/65/73\x1b\\ ``` 注意 1 列处无制表位(本即光标 home),斜杠仅分隔不终止。DCS 前缀 `\x1bP2$u` 回显请求的 `2$` 加上 `u` 表示「unsolicited / response」(类比 DECRQSS 的 `$r`)。 **往返模式**(TUI 会话前后保存 / 恢复终端制表状态): ``` 启动: 发 \x1b[2$w -> 收 \x1bP2$u9/17/25/...\x1b\\ 解析:以 '/' 分割体 -> [9, 17, 25, ...] 保存 stops_before 退出: 发 \x1b[3g # TBC 清全部 for col in stops_before: 发 \x1b[<col>G\x1bH # CHA 至 col,HTS 于 col ``` 声明 `dectabsr` 的 terminfo 条目里,`tput rs2` 做的就是这件事 —— 「重置到已知制表状态」用读 + 还原,而不是傻发 `\x1b[?5W`(DECST8C —— 设 8 列制表)。 **边界**: - 空回复(`\x1bP2$u\x1b\\`)表示一个制表位都没有 —— 发 `\x1b[?5W` 或写一串 HTS 还原默认。 - 部分模拟器会把隐含的「行尾」位(列 == 屏宽 + 1)也报出来 —— 从保存列表里剥除。 - 回复默认以 `\x1b\\`(ST 表示为 ESC + 反斜杠)结束;xterm 在 8 位 C1 模式下(见 `decscl-compat-level`)使用单字节 `\x9c`。 **覆盖度**:**xterm** = 完整(标准)。**WezTerm** / **mlterm** / **Konsole** = 完整。**Ghostty** = 部分(回但总是默认 8 列)。**Kitty** / **iTerm2** = 部分(回但某些代码路径漏掉用户设置的位)。**Alacritty** / **Linux console** / **Windows Terminal** / **cmd / ConPTY** / **macOS Terminal** / **gnome-terminal** = 无作用(完全不回 —— 探测务必加 ~100 ms 超时)。

规范出处: DEC VT510 RM (DECTABSR / DECRPTAB) / xterm-ctlseqs (CSI 2 $ w)

示例

bash
# Probe tab stops; read DCS reply with timeout.\nprintf '\\033[2$w'\nIFS= read -rs -d '\\\\' -t 0.1 reply </dev/tty 2>/dev/null\necho \"DECTABSR: ${reply}\"   # expect: \\x1bP2$u9/17/25/...
python
import sys, re\n# Parse the slash-separated tab list from a DECRPTAB reply.\nreply = '\\x1bP2$u9/17/25/33/41/49/57/65/73\\x1b\\\\'\nm = re.search(r'\\x1bP2\\$u([\\d/]*)\\x1b\\\\', reply)\nstops = [int(c) for c in m.group(1).split('/') if c] if m else []\nprint(stops)
go
// Save-then-restore tab stops across a TUI's runtime.\nfmt.Print(\"\\x1b[2$w\")              // request DECTABSR\n// ... read DCS reply, parse to []int ...\n// On exit: TBC all, then HTS at each saved col\nfmt.Print(\"\\x1b[3g\")               // TBC 3 clears all\nfor _, col := range saved {\n    fmt.Printf(\"\\x1b[%dG\\x1bH\", col)\n}
javascript
// Detect 'no tab stops at all' (empty body).\nfunction parseDECTABSR(buf) {\n  const m = /\\x1bP2\\$u([^\\x1b]*)\\x1b\\\\/.exec(buf);\n  if (!m) return null;\n  return m[1].split('/').filter(s => s.length).map(Number);\n}\nconsole.log(parseDECTABSR('\\x1bP2$u\\x1b\\\\'));   // [] — no tabs at all
c
/* Skeleton: probe + parse (cbreak stdin, timed read). */\nprintf(\"\\x1b[2$w\"); fflush(stdout);\n/* read until ST (0x1b 0x5c). then strtok on '/' between \"$u\" and ST. */

终端支持

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

相关序列