Skip to content

fix(editor): preserve original text file encoding - #523

Merged
Menghuan1918 merged 2 commits into
omdsh-dev:devfrom
wang-kaopu:fix/506-gbk-encoding
Oct 4, 2026
Merged

Menghuan1918 merged 2 commits into
omdsh-dev:devfrom
wang-kaopu:fix/506-gbk-encoding

Conversation

@wang-kaopu

@wang-kaopu wang-kaopu commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

说明

Windows 中文环境中的 GBK/CP936 脚本和配置文件此前会被内置编辑器直接按 UTF-8 解码,导致中文乱码;同时编辑后保存会固定以 UTF-8 写回,存在静默改变原文件编码的问题。

Duplicate report: #506;canonical issue: #406。

改动

  • 读取文本时自动检测 UTF-8、UTF-8 BOM、UTF-16 LE/BE、UTF-32 LE/BE、GBK/CP936 和 GB18030
  • 在编码识别之后再执行 NUL 二进制判定,避免 UTF-16/UTF-32 文本被误判为二进制文件
  • 支持无 BOM UTF-16 LE/BE 脚本的启发式识别
  • 保存已有文件前重新检测磁盘编码,并按原编码写回
  • 新文件保持现有行为,默认使用 UTF-8
  • GBK 遇到无法表示的字符时拒绝有损保存,避免静默替换内容
  • 补充编码 round-trip、截断读取、二进制判定和保存编码检测测试

验证

  • pnpm typecheck
  • pnpm test
  • pnpm build
  • consumer type surface 检查
  • 真实 DSH 插件挂载冒烟测试

Fixes #406

@wang-kaopu
wang-kaopu marked this pull request as draft September 3, 2026 02:59
@wang-kaopu
wang-kaopu marked this pull request as ready for review September 3, 2026 03:09

Copy link
Copy Markdown
Contributor Author

已基于最新 main 重新整理分支,当前为 ahead 1 / behind 0,PR 已恢复为 mergeable;关联也已改为 canonical #406(#506 标注为 duplicate report)。当前 CI 三个 lane 均已通过,现已 ready for review。

@HuanLinOTO HuanLinOTO added bug Something isn't working area/editor File editor + preview (markdown / HTML / code / mermaid) P2 中:一般功能/优化 labels Oct 1, 2026
冲突只有两处上下文搬迁,均在 src/index.ts:
- 导入块:保留 dev 的 fs-batch / active-worktree 两行(含其注释),其后追加
  PR 的 text-encoding 导入。
- fs.write:保留 dev 的写路由新形状(每请求唯一临时名 + flag:'wx'),
  并把 PR 的 encodeText(content, encoding) 接进去(encoding 仍在重命名前
  用 encodingOfFile(path) 从磁盘上的原文件探测)。

一并修掉证据实测的截断误判:读上限(readLimit / 64KiB 嗅探窗口)落在多字节
字符中间时,残留的部分字节会被 GBK 探测当成一个合法双字节字,导致 > 上限的
UTF-8 文件整段乱码、保存还可能按错编码落盘(Node v26 实测:三字节汉字缺 2
字节时 utf8=fatal 失败、gbk=成功)。现 decodeTextBytes 接受 truncated 标记,
在截断且尾部确为不完整 UTF-8 序列时按 UTF-8 处理(内容仍沿用原先的 U+FFFD
渲染);完整但不合法的尾部序列照旧交给传统编码探测。测试补齐:单测(三字节 /
四字节截断、完整非法序列不被误裁、>64KiB 嗅探边界)+ 路由级(GBK round-trip、
512KiB readLimit 截断的中文 UTF-8 读取)。

Refs omdsh-dev#523
@Menghuan1918
Menghuan1918 changed the base branch from main to dev October 4, 2026 17:50
@Menghuan1918
Menghuan1918 merged commit 9b97e6f into omdsh-dev:dev Oct 4, 2026
2 of 3 checks passed
@Menghuan1918

Copy link
Copy Markdown
Collaborator

已把 dev 侧的解冲突结果回填到这个分支,基分支改为 dev,然后合并(你的提交原样保留,未 rebase / 未 squash)。

冲突 2 处,都在 src/index.ts:dev 期间写路由换成了「每请求唯一临时名 + flag: 'wx' 独占创建 + rename」的原子写形状。我保留了 dev 的新形状,同时把你的编码逻辑接进去——写临时文件前先 encodingOfFile(path)(仍探测磁盘上的原文件),写入用 encodeText(content, encoding)。两边意图都成立,没有取舍;readText 的两个 hunk 原样套用。

另外我修了你顺手提到的那个「截断误判」(它确实会误伤):大文件按 readLimit 截断读取时,如果切口正好落在汉字中间,尾部会留下不完整的多字节序列,UTF-8 fatal 解码失败后就被判成 GBK,整屏乱码。修法是截断时先裁掉尾部不完整序列再判定:新增 hasIncompleteUtf8Tail(),decodeTextBytes(bytes, truncated) 在 UTF-8 失败之后、传统编码探测之前判为 utf8(内容仍按 U+FFFD 渲染,不丢尾部字节);完整但不合法的尾部序列(如 0xC0 0x80)照旧交给传统编码探测,二进制判定不受影响(NUL 检查在前)。本机复现过原缺陷:中文测试内容 的 UTF-8 前缀缺 2 字节时 utf8=fatal 而 gbk 成功(解出「涓枃娴嬭瘯鍐呭」)。

配套加了测试:tests/text-encoding.spec.ts 三/四字节截断、完整非法尾部不误裁、>64KiB 嗅探边界落在汉字中间;tests/smoke.spec.ts 路由级 GBK round-trip(读回原文 + 保存后磁盘字节仍是原 GBK 字节)与 512KiB 截断中文读取。同样做了红检:临时让修复失效,这 3 条新用例全红,恢复后 73/73 绿。

门禁:pnpm typecheck 0;全量 vitest 154 files / 1715 passed / 13 skipped;eslint 0;tests/text-encoding.spec.ts 15 passed。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/editor File editor + preview (markdown / HTML / code / mermaid) bug Something isn't working P2 中:一般功能/优化

Projects

Development

Successfully merging this pull request may close these issues.

文件预览/编辑器:ANSI(GBK/GB2312)文件打开乱码,保存会悄悄转成 UTF-8(附零依赖完整修复 patch)

3 participants