|
| 1 | +# 任务 0969:修复 LLM 插件输出 emoji 乱码 |
| 2 | + |
| 3 | +## 问题 |
| 4 | + |
| 5 | +llm 商业版中发现 LLM 回复中的 emoji(如 😊)显示为乱码;在 mogan 自带的 |
| 6 | +llm 假插件(`TeXmacs/plugins/llm`,Insert → Session → LLM)可稳定复现。 |
| 7 | +用户提供的 `你是谁.tmu` 中,原应为 😊 的位置存储的是 `C3 BF C2 98 C2 8A` |
| 8 | +(即 U+00FF U+0098 U+008A),屏幕上显示为 `ÿ` 加两个缺字形方块。 |
| 9 | + |
| 10 | +## 根因 |
| 11 | + |
| 12 | +Mogan 会话输出链路:插件子进程 stdout → `texmacs_input_rep::utf8_flush` |
| 13 | +(`src/Data/Convert/Generic/input.cpp`)→ `tree_utf8_to_herk` → 文档内部 |
| 14 | +herk 编码。UTF-8 → herk 方向(`lolly::data::utf8_to_herk`)把映射不到单字节的 |
| 15 | +码点正确逃逸为 `<#XXXX>`(如 😊 U+1F60A → `<#1F60A>`)。 |
| 16 | + |
| 17 | +但反向 `lolly::data::herk_to_utf8` 的辅助函数 `append_utf8_code` |
| 18 | +(`lolly/lolly/data/herk.cpp`)只有 1/2/3 字节 UTF-8 分支,缺 4 字节分支。 |
| 19 | +对 ≥ U+10000 的码点按 3 字节形式截断编码: |
| 20 | + |
| 21 | +- U+1F60A:`0xE0|(code>>12)`=0xFF、`0x80|((code>>6)&0x3F)`=0x98、 |
| 22 | + `0x80|(code&0x3F)`=0x8A → 输出非法 UTF-8 字节 `FF 98 8A`; |
| 23 | +- 下游(聊天 tab 显示、.tmu 保存)把这三个坏字节按 Latin-1 逐字节再编码为 |
| 24 | + `C3 BF C2 98 C2 8A`,与 .tmu 文件中观察到的乱码逐字节吻合。 |
| 25 | + |
| 26 | +对比:cork 侧同功能的 `cork_to_utf8` 走 `encode_as_utf8` |
| 27 | +(`lolly/lolly/data/unicode.cpp`),有完整 4 字节分支,不受影响; |
| 28 | +全库仅 `herk.cpp` 的 `append_utf8_code` 一处缺该分支。 |
| 29 | + |
| 30 | +受影响路径(均经 `herk_to_utf8`/`tree_herk_to_utf8`):会话/聊天输出还原、 |
| 31 | +`connection.cpp:266` 插件输入序列化、`edit_complete.cpp:359`、 |
| 32 | +`QTMMenuhelper.cpp:93`、`smart_font.cpp:865`,以及 Scheme glue |
| 33 | +`herk->utf8` / `tree-herk->utf8-tree`。 |
| 34 | + |
| 35 | +## 修复 |
| 36 | + |
| 37 | +- `lolly/lolly/data/herk.cpp`:`append_utf8_code` 补上 |
| 38 | + `code < 0x10000` 的 3 字节分支与 `code <= 0x1FFFFF` 的 4 字节分支, |
| 39 | + 超出 Unicode 上限的输入不再编码(与 `encode_as_utf8` 行为对齐)。 |
| 40 | + |
| 41 | +## 测试 |
| 42 | + |
| 43 | +- `lolly/tests/lolly/data/herk_test.cpp` 新增 `herk_4byte_codepoints` 用例: |
| 44 | + U+1F60A/U+1F642/U+20000/U+10FFFF 的 `<#XXXX>` → UTF-8 往返,及混合文本 |
| 45 | + `A<#1F60A>B` 的还原。 |
| 46 | +- 运行 `xmake test lolly_tests/herk_test`(仓库根目录):修复前新用例 |
| 47 | + 失败(复现 bug),修复后 38 用例 635 断言全部通过。 |
| 48 | +- GUI 手工验证(Insert → Session → LLM,假插件回显含 😊 的消息)由用户执行。 |
| 49 | + |
| 50 | +## 涉及文件 |
| 51 | + |
| 52 | +- `lolly/lolly/data/herk.cpp`(修复) |
| 53 | +- `lolly/tests/lolly/data/herk_test.cpp`(回归测试) |
| 54 | +- `devel/0969.md`(本文档) |
0 commit comments