跳到主要内容
ansicode

HTS — 水平制表位设置(ESC H)

在当前光标列设置一个 tab 停位 —— 与 TBC 互为伙伴。

字节形式

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

\\x1b[\x1bH
\\033[\033H
\\e[\eH
ESC [ESC H
hex1b 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 网格的工具(columnprexpandmake 配方输出)在你重定义网格后可能出现意外列对齐 —— 写代码要有防御意识,并在结束时自行清理。

两点运维细节。其一,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)

示例

bash
printf '\033[3g'                # clear all\nprintf '\033[10G\033H\033[20G\033H'   # set tab stops at cols 10 and 20
python
import sys; sys.stdout.write('\x1bH')
go
fmt.Print("\x1bH")
javascript
process.stdout.write('\x1bH')
c
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
支持

相关序列

在家族食谱中

ESC 食谱 · 2. 制表位 —— `\x1bH`(HTS)设、`\x1b[g`(TBC)清