fix: terminal garbled boxes from OSC sequences in PS1

User reported: each prompt line shows a leading '[?]' box.
Root cause: Ubuntu's default PS1 uses \\e]0;user@host:dir\\a
(OSC 0, set window title) which our ANSI parser did not recognize.
It only handled SGR (\\e[...m), so the raw bytes were drawn as tofu boxes.

Fix in ui/terminal_panel.py:
- Added _OSC_RE for ESC ] ... BEL|ESC\\ sequences (set title, set cwd)
- Added _DCS_RE for ESC P/X/^/_ ... ESC\\ (DCS/SOS/PM/APC)
- _on_data() branches ESC prefix by next byte: '['->CSI, '] '->OSC,
  'P/X/^/_'->DCS, others->skip 2 bytes
- Captured OSC 0/1/2 content into self._window_title (so future
  versions can display it)
- _strip_ansi() now also strips OSC/DCS (for clean history recall)

Added [4b/5] test: injects a literal Ubuntu PS1 byte stream
(OSC 0 + SGR colors) and verifies the rendering is just the plain
'root@ubuntu2204:~# ' with no tofu / no leaked escape chars.

All 21 tests pass (core 6 + UI 3 + E2E 6 + terminal 6).
This commit is contained in:
Hermes
2026-07-28 21:46:26 +08:00
parent 9dbd500399
commit 1b7259c2d5
2 changed files with 64 additions and 9 deletions
+19
View File
@@ -99,6 +99,25 @@ def main():
assert wait_for_text(panel, "GREEN", timeout_s=5)
print(f" ✓ ANSI 颜色输出已渲染")
# 额外:直接注入一段带 OSC 0 提示符的字节,验证不显示乱码框
print("[4b/5] 注入 Ubuntu 默认 PS1 字节(带 OSC 0 标题)")
panel.term.clear()
panel._current_line_start = 0
# Ubuntu 默认 PS1: \[\e]0;...\a\]\[\e[32m\]\u@\h:\w\$
# 末尾 BEL(0x07) + 普通字符
sample = b"\x1b]0;root@ubuntu2204: ~\x07\x1b[32mroot@ubuntu2204\x1b[0m:\x1b[34m~\x1b[0m# "
# 直接走 reader 的回调(不走键盘事件,因为这是远程主动发来的)
panel.reader.data_received.emit(sample.decode("utf-8", errors="replace"))
QApplication.processEvents()
text = panel.term.toPlainText()
# 不应该看到 OSC 里的 0;root@... 这种字面字符
assert "]0;root@ubuntu2204" not in text, f"OSC 0 没被吞掉: {text!r}"
assert "[32m" not in text, f"CSI SGR 没被吞: {text!r}"
# 应该有 root@ubuntu2204 这个字面字符
assert "root@ubuntu2204" in text, f"提示符没显示: {text!r}"
print(f" ✓ OSC 标题被正确吞掉,提示符字面字符显示正常: {text!r}")
print("[5/5] 验证本地历史(↑键)")
panel.history.append("ls /tmp") # 模拟已经执行过的命令
panel.history_idx = -1