HTS — 水平制表位设置(ESC H)
在当前光标列设置一个 tab 停位 —— 与 TBC 互为伙伴。
字节形式
涵盖所有常见的字符串字面量写法,方便正反查找。
\x1bH\033H\eHESC H1b 48说明
ECMA-48 §8.3.62 —— 水平制表位设置(HTS)。两字节 ESC 序列:ESC(0x1b)后跟 H(0x48)。无 CSI 引导符、无参数 —— 当前光标列即为隐式操作数。HTS 在光标当前列设置一个 tab 停位;与 TBC(\x1b[g / \x1b[3g,见 csi-tbc,清除停位)配对。每个终端初始化时都有每 8 列一个 tab 停位(9、17、25 …)—— HTS 就是用来覆盖这套默认 8 列网格、改用与表单 / 表格 / 列对齐输出匹配的自定义布局的原语。HTS 的 terminfo 能力名为 hts。
可移植性 —— xterm、iTerm2、kitty、alacritty、wezterm、gnome-terminal、Konsole、Ghostty、Linux console、Windows Terminal 通用。Windows 旧 cmd.exe(ConPTY 之前)忽略 HTS;ConPTY 支持。多停位布局的标准流程:\x1b[3g 抹掉默认 8 列网格 → 对每个目标列,用 HPA / CHA(\x1b[<col>G)把光标移过去再发 \x1bH → 完成。此后每个 \t(HT,0x09)或 \x1b[<n>I(CHT —— Cursor Forward Tabulation,见 csi-cht)都按自定义停位推进。依赖 *默认* tab 网格的工具(column、pr、expand、make 配方输出)在你重定义网格后可能出现意外列对齐 —— 写代码要有防御意识,并在结束时自行清理。
两点运维细节。其一,HTS 状态是「每终端窗口」而非「每 tmux / screen pane」。tmux 把内部 pseudo-terminal 的 tab 停位规范化为默认 8 列网格,因此 pane 内发出的 \x1bH 在多路复用器边界被截留,不会转发到外层终端;GNU screen 同样。其二,该状态不会被 SGR 0、Ctrl+L(换页 \x0c)或普通清屏(\x1b[2J)触碰 —— tab 停位跨屏幕、跨回滚 flush、跨多数 reset 路径持久存在。只有 \x1b[3g(TBC 参数 3 —— 清除全部)、DECSTR(\x1b[!p,见 decstr-soft-reset)或 RIS(\x1bc)能重置。需要已知干净 tab 网格的程序(格式化器、表格布局、自定义 REPL)的防御性写法是:在设置自己的停位 *之前* 先发 \x1b[3g,绝不假定默认 8 列网格仍完整 —— 同一会话中之前的程序可能留下了自定义网格。相关:csi-tbc(TBC —— 配套的「清除 tab 停位」一半)、csi-cht(CHT —— HT 的「按停位前进 N 次」可带参数形式)、c0-controls(C0 表,含 HT \x09 —— 触发推进的字面 tab 字符)。
规范出处: ECMA-48 §8.3.62 (HTS)
示例
printf '\033[3g' # clear all\nprintf '\033[10G\033H\033[20G\033H' # set tab stops at cols 10 and 20import sys; sys.stdout.write('\x1bH')fmt.Print("\x1bH")process.stdout.write('\x1bH')printf("\x1bH");在哪里用到
实际会发出该序列的工具——把抽象字节锚定到你已经用过的命令上。
- GNU `expand` / `unexpand` tab-grid metadata`expand -i -t 4,8,12,16` 自身不发 HTS(它在流中把 tab 展开为空格),但 `unexpand --first-only -t 4,8,12,16` 读取保留-tab 流时在终端预览输出的每个网格边界发 HTS,以恢复原始 tab 停位布局保证往返保真
- vim / neovim `:set tabstop=4,8,12`vim 的 `:set tabstop=4,8,12`(可变 tabstop,≥ 7.3)发 `\x1b[3g` 加一连串 CHA + `\x1bH` 调用,为编辑器会话期间重设终端 tab 网格 —— `:set verbose=15` 可见。`:q` 时通过 DECSTR 清理
- BSD ed `T` commandBSD `ed` 的 `T`(set-tab)命令,遗留模式 `T8,16,24` 在 `\x1b[3g` 清全部后于每个指定列发 HTS —— 历史上用于格式化打孔卡时代 tab 列非 8 倍数的数据文件。NetBSD / FreeBSD `ed(1)` 仍保留
- terminfo `hts` cap (queryable via `tput hts`)`tput hts` 查询 `hts` 能力并发出终端特定的 HTS 字节 —— `xterm-256color` 等都映射到 `\x1bH`(标准两字节形)。脚本需要可移植地铺设自定义列网格时用 `tput hts` 而非硬编码 `\033H`
- Emacs `tab-stop-list` recalculationGNU Emacs 在 `tty` 帧下,当 `tab-stop-list` 设为自定义布局(`(setq tab-stop-list '(4 8 16 24))`)时,通过 `term-emulate-terminal` 发 HTS —— 与帧入口的 `\x1b[3g` 配对。`script` 捕获 TTY 输出后 grep `\x1bH` 可见
终端支持
- 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 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 支持 | 支持 | 支持 | 支持 | 支持 | 部分 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |