DECAWM ?7 — 自动换行模式
切换光标到达右边距时是否自动换到下一行(默认开启)。
字节形式
涵盖所有常见的字符串字面量写法,方便正反查找。
\x1b[?7h (enable wrap) \x1b[?7l (disable)\033[?7h / \033[?7l\e[?7h / \e[?7lESC [ ? 7 h / l1b 5b 3f 37 68 / 6c说明
DEC 自动换行模式(DECAWM)—— DEC 私有模式 7,记录于 xterm-ctlseqs 与最早的 VT100 参考手册,是最早的 DEC 模式之一。启用字节序列为 \x1b[?7h(终端的*初始*状态 —— 自动换行默认开),关闭为 \x1b[?7l。换行启用时,超出最右列的字符会换到下一行的第 1 列,若光标在最后一行则滚动视口。换行关闭后,光标停在末列,新字符在原位覆盖前一个 —— 这对状态栏和 TUI 在屏幕边缘精确绘制(避免意外滚动)非常有用。「幻影列」行为是 DECAWM 开启下的特性:把字符写入末列时,光标处于延迟态(视觉上在第 N 列,但下次写入会触发换行而非覆盖),让终端在滚动前多出一列容量 —— 这是无数 TUI 差一错的根源。
模拟器间的可移植面异常一致,因为 DECAWM 是最古老的 DEC 模式之一 —— Linux console / fbcon 实现,ConPTY 1809+ 转发(ConPTY 之前的旧 cmd.exe 把 ?7l 视为空操作且始终换行),Apple Terminal.app / iTerm2 / kitty / alacritty / wezterm / gnome-terminal / Konsole / Ghostty / Windows Terminal 都实现两种状态。陷阱在 wrap-at-eol-confusion pitfall:许多 TUI 库在客户端跟踪光标位置时,会在终端实际换行*之前*一列就*预测*换行(因为前述幻影列行为),与终端关于光标位置的认知不一致 —— 表现为绘制的字符出现在错位的一行上,全屏 TUI 右下角尤其明显。客户端 TUI 代码的修复方法是:要么在引发该问题的写入后用 DSR \x1b[6n 查询光标位置,要么在边缘精确绘制期间设 ?7l 并依赖显式定位。tmux 按 pane 遵守 DECAWM;screen 4.x 与 5.0 都遵守,但若中间发生外层终端 resize,每个窗口的状态在 detach / reattach 间不一定能正确往返。
使用 \x1b[?7l 关闭、\x1b[?7h 恢复。把终端交还给用户之前务必恢复 —— 否则用户的 shell 提示符与命令行编辑器会表现异常(长行明显被截断,readline 的光标计算与显示位置不一致)。健壮模式是 XTSAVE / XTRESTORE(\x1b[?7s / \x1b[?7r),让退出时的状态匹配父进程原状,而非无条件开。DECAWM 还与 DECOM(?6 —— origin mode,控制光标坐标参考是全屏还是滚动区域)以及 DECSTBM(CSI r —— 设滚动边距)相互作用:在 DECOM 也激活时,边缘换行是在*滚动区域内*换行。相关:alt-screen(TUI 进入 alt-screen 后通常切到 ?7l 做边缘精确绘制)、cursor-position(CUP —— 幻影列绊倒你时替代客户端位置预测)、dec-origin-mode(与 DECAWM 联合决定真实换行边界的 DECOM 模式)。
规范出处: xterm-ctlseqs (DEC Private Mode 7, DECAWM)
示例
printf '\033[?7l' # disable wrap for status bar\nprintf '\033[?7h' # restoreimport sys; sys.stdout.write('\x1b[?7l')fmt.Print("\x1b[?7l")process.stdout.write('\x1b[?7l')printf("\x1b[?7l");在哪里用到
实际会发出该序列的工具——把抽象字节锚定到你已经用过的命令上。
- cat, less long-line behaviourDECAWM 打开(`\x1b[?7h`,默认)时长行在右边距换行;`less -S` 切换到水平滚动模式,对可见行而言语义等价于关闭 DECAWM
- vim, neovim `:set wrap` / `:set nowrap``textwidth` 与 `wrap` 与 DECAWM 互动 —— `nowrap` 依赖终端在右边距的 DECAWM-off 行为,让编辑器自身的水平滚动接管
- tput rmam / tput smam`tput rmam` 发 `\x1b[?7l`(关自动边距 / DECAWM reset),`tput smam` 发 `\x1b[?7h` —— 用于绘制定宽表格的 curses 脚本,不希望第 N 列的杂字触发隐式换行
- column, pr, fmt fixed-width output按列对齐的输出假设 DECAWM 打开(默认)且终端遵守右边距换行 —— 超长行优雅地降级到新行而非截断
- GNU readline / bash line-editingreadline 跟踪 DECAWM 状态以计算提示符换行点;判错会让换行后光标落到错误行(经典的 `\[ \]` PS1 转义 bug 即源于此)
常见问题
针对这条序列,开发者真正会去搜索的问题的简短回答。
- DECAWM 启用时,为什么 TUI 的列有时会错位一格?
- 「幻影列」问题。
?7h下(默认),把字符写到末列时*不立即*换行 —— 终端把光标置于延迟态,*下一次*写入才触发换行。可见光标在第 N 列,但下个字符落到下一行的第 1 列。客户端追踪光标位置的 TUI 库常常提前一列预测换行,与终端的认知不一致。修复方法:(a) 在靠近右边距的写入后用 DSR\x1b[6n(见csi-dsr)查询实际位置,或 (b) 在边缘精确绘制期间切到?7l并用 CUP 显式定位,交还控制权前恢复?7h。 - 程序退出时把
\x1b[?7l留作设置安全吗? - 不安全 —— 永远别让 wrap-off 作为退出状态。用户的 shell 提示符、基于 readline 的命令编辑器、
less/man都会行为异常:长输入行在右边距处视觉截断,而 readline 的光标计算继续推进,造成经典的「输入掉出屏幕」症状。务必在终端恢复的 atexit / 信号处理器里恢复\x1b[?7h(或用 XTSAVE / XTRESTORE 对\x1b[?7s/\x1b[?7r还原父进程原状)—— 含 SIGINT、SIGTERM 与崩溃路径。健壮模式:启动时\x1b[?7s保存、期间设\x1b[?7l、退出时\x1b[?7r恢复。与恢复?25(光标可见性)、?1049(alt-screen)、?1000+(鼠标模式)天然配对 —— 是完整的 TUI 退出卫生检查表。
终端支持
- 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 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 支持 | 支持 | 支持 | 支持 | 支持 | 部分 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |