概述
在 iTerm2 上,用中文输入法向 TUI 输入框提交文字,什么都不会出现 —— 没有字符,
没有乱码,也没有报错。同一个会话里敲英文一切正常。设置
TEXTUAL_DISABLE_KITTY_KEY=1 之后完全恢复。
这跟 apodex/tui/ime.py 已经处理的那个问题不是同一回事。那个模块修的是
「超长提交被还原成可见乱码」(^[32;;26377:24456:...u)。而这里是一个字节都没有
产出,所以现有的修复根本没有机会介入。
环境
|
|
| 终端 |
iTerm2 3.6.11(build 3.6.11) |
| 系统 |
macOS,Darwin 25.2.0(Apple Silicon) |
| textual |
8.2.8 |
| 模式 |
--mode react,全屏 TUI |
TERM / COLORTERM |
xterm-256color / truecolor |
| 输入法 |
macOS 自带拼音 |
复现步骤
- 在 iTerm2 里启动 TUI:
uv run frontier-agent --mode react
- 焦点放到输入框,切到中文输入法,打拼音,从候选窗口按空格/回车提交
- 输入框里什么都没有。同一个输入框里敲英文正常
- 加上
TEXTUAL_DISABLE_KITTY_KEY=1 重启 —— 中文输入恢复正常
提交前我先验证过的事
widen_escape_sequence_limit() 确实被调用了(apodex/tui/app.py:449),而且在
textual 8.2.8 上确实生效 —— _MAX_SEQUENCE_SEARCH_THRESHOLD 仍然存在,默认值
仍然是 32。把 ime_commit_sequence() 直接喂给 XTermParser,行为跟 ime.py 里写的
分析完全一致:
from textual._xterm_parser import XTermParser
from apodex.tui.ime import ime_commit_sequence, widen_escape_sequence_limit
| 提交内容 |
序列长度 |
阈值 32(上游默认) |
阈值 512(修复后) |
你好世界(4 字) |
29 |
4 个正确的 Key 事件 |
4 个正确的 Key 事件 |
有很大差别(5 字) |
36 |
36 个乱码 Key 事件(^、[、3、2…) |
5 个正确的 Key 事件 |
我需要中文打字啊(8 字) |
54 |
54 个乱码 Key 事件 |
8 个正确的 Key 事件 |
也就是说,解析器层面的这个修复是可靠的。既然「加宽阈值能正确解析这些序列」是可证明的,
而我们在 iTerm2 上观察到的是零个事件、而不是错误的事件,那么结论只能是:
提交的文本压根没有以 Kitty 关联文本序列的形式抵达解析器 —— 丢失发生在
_xterm_parser 的上游。
我还没有抓到 iTerm2 在 CSI > 25 u 模式下实际发出的原始字节,所以无法区分是
iTerm2 没有实现 KITTY_REPORT_ASSOCIATED_TEXT、还是声称支持但提交时不发文本、
还是别的原因。需要的话我可以补一份字节 trace。
为什么值得修
iTerm2 是 macOS 上占比很高的终端,而这个失效是静默的:没有报错,没有乱码,
也没有任何迹象暗示背后是一次键盘协议协商。一个中文用户最自然的结论是「这个 TUI
不支持中文」。README 和 --help 里也没有任何地方提到 TEXTUAL_DISABLE_KITTY_KEY。
建议的修法,按成本从低到高
- 先写进文档。 README 的故障排查里加一行
TEXTUAL_DISABLE_KITTY_KEY=1,
就能省掉整个排查过程。
- 检测并降级。 环境变量里能拿到
TERM_PROGRAM=iTerm.app;在这类终端上可以
干脆不发 Kitty 请求(或者先用 CSI ? u 查询、检查关联文本那一位),
等 iTerm2 支持了再启用。
- 让现有的静默失效发出声音 —— 见下。
附带问题:widen_escape_sequence_limit() 在一种有歧义的情况下会静默失效
current = getattr(_xterm_parser, "_MAX_SEQUENCE_SEARCH_THRESHOLD", None)
if not isinstance(current, int):
logger.debug("textual no longer exposes the escape-sequence limit")
return 0
文档字符串的理由是:常量不存在意味着「要么上游已经修了,要么挪了地方,两种情况下
静默跳过都是对的」。但这两种情况的后果是相反的 —— 如果常量只是被改了名字而
截断行为依然存在,这个兜底就会悄无声息地停止工作,中文输入随之回归损坏,
而且在任何用户看得到的日志级别上都不会有提示。debug 不够,改成 warning
成本为零,却能让这类回归被发现。
概述
在 iTerm2 上,用中文输入法向 TUI 输入框提交文字,什么都不会出现 —— 没有字符,
没有乱码,也没有报错。同一个会话里敲英文一切正常。设置
TEXTUAL_DISABLE_KITTY_KEY=1之后完全恢复。这跟
apodex/tui/ime.py已经处理的那个问题不是同一回事。那个模块修的是「超长提交被还原成可见乱码」(
^[32;;26377:24456:...u)。而这里是一个字节都没有产出,所以现有的修复根本没有机会介入。
环境
--mode react,全屏 TUITERM/COLORTERMxterm-256color/truecolor复现步骤
uv run frontier-agent --mode reactTEXTUAL_DISABLE_KITTY_KEY=1重启 —— 中文输入恢复正常提交前我先验证过的事
widen_escape_sequence_limit()确实被调用了(apodex/tui/app.py:449),而且在textual 8.2.8 上确实生效 ——
_MAX_SEQUENCE_SEARCH_THRESHOLD仍然存在,默认值仍然是 32。把
ime_commit_sequence()直接喂给XTermParser,行为跟ime.py里写的分析完全一致:
你好世界(4 字)Key事件Key事件有很大差别(5 字)Key事件(^、[、3、2…)Key事件我需要中文打字啊(8 字)Key事件Key事件也就是说,解析器层面的这个修复是可靠的。既然「加宽阈值能正确解析这些序列」是可证明的,
而我们在 iTerm2 上观察到的是零个事件、而不是错误的事件,那么结论只能是:
提交的文本压根没有以 Kitty 关联文本序列的形式抵达解析器 —— 丢失发生在
_xterm_parser的上游。我还没有抓到 iTerm2 在
CSI > 25 u模式下实际发出的原始字节,所以无法区分是iTerm2 没有实现
KITTY_REPORT_ASSOCIATED_TEXT、还是声称支持但提交时不发文本、还是别的原因。需要的话我可以补一份字节 trace。
为什么值得修
iTerm2 是 macOS 上占比很高的终端,而这个失效是静默的:没有报错,没有乱码,
也没有任何迹象暗示背后是一次键盘协议协商。一个中文用户最自然的结论是「这个 TUI
不支持中文」。README 和
--help里也没有任何地方提到TEXTUAL_DISABLE_KITTY_KEY。建议的修法,按成本从低到高
TEXTUAL_DISABLE_KITTY_KEY=1,就能省掉整个排查过程。
TERM_PROGRAM=iTerm.app;在这类终端上可以干脆不发 Kitty 请求(或者先用
CSI ? u查询、检查关联文本那一位),等 iTerm2 支持了再启用。
附带问题:
widen_escape_sequence_limit()在一种有歧义的情况下会静默失效文档字符串的理由是:常量不存在意味着「要么上游已经修了,要么挪了地方,两种情况下
静默跳过都是对的」。但这两种情况的后果是相反的 —— 如果常量只是被改了名字而
截断行为依然存在,这个兜底就会悄无声息地停止工作,中文输入随之回归损坏,
而且在任何用户看得到的日志级别上都不会有提示。
debug不够,改成warning成本为零,却能让这类回归被发现。