Skip to content

fix(editor): restore document editing and source-preserving undo - #2818

Merged
wgqqqqq merged 2 commits into
GCWing:1.0.0-explorefrom
wgqqqqq:wgq/markdown-document-editing
Sep 5, 2026
Merged

wgqqqqq merged 2 commits into
GCWing:1.0.0-explorefrom
wgqqqqq:wgq/markdown-document-editing

Conversation

@wgqqqqq

@wgqqqqq wgqqqqq commented Sep 5, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Restore editable Markdown documents with two modes: Document / Source (文档 / 源码). Ordinary text stays directly editable when the document contains embedded syntax, and the document view reuses the existing preview typography and component styles.

  • Edit Mermaid, HTML, equations, frontmatter, image properties, and unsupported Markdown regions through local source editors; keep their original rendered appearance outside editing.

  • Preserve dirty state, save shortcuts, readonly behavior, and undo/redo across native and embedded editing. Renderer failures leave an editable source fallback.

  • Associate imported Markdown bytes with their rich document state. Undoing back to that state restores the original source, including list delimiters, whitespace, and line endings, so formatting normalization does not leave a false dirty marker.

  • Reload local images through the workspace file adapter when their source changes; ignore stale image requests so they cannot overwrite a newer image.

  • Resolve source-backed reference blocks against shared document context, preserving footnote numbering, definitions, and navigation without duplicating bodies or changing saved Markdown.

Type and Areas

Type: regression fix / UI/UX / tests

Areas: Web UI Markdown editor; shared Markdown presentation; local desktop integration tests; locales.

Motivation / Impact

Markdown files had regressed to preview plus source editing. This restores document editing without redesigning their appearance or forcing an entire document into preview because of special syntax.

For example, opening a file containing * item, editing its heading, and undoing previously regenerated - item: the visible content was restored, but the tab remained dirty. The editor now returns the exact imported source at the restored document state. Partial undo and intentional source-formatting edits remain dirty, and undo/redo after saving is compared with the latest saved bytes.

Verification

Validation for the image-loading and footnote-context fixes in c9670e187:

  • Focused editor and shared Markdown suites listed in src/web-ui/src/tools/editor/AGENTS.md — 104 tests passed across 9 files. Coverage includes stale image request success/failure, shared footnote numbering, unique anchors, reference links/images, and navigation across render regions.
  • pnpm --dir tests/e2e exec wdio run ./config/wdio.markdown-browser.ts — 10 tests passed. Added browser coverage for editing footnote definitions and save/reload, and changing image addresses through the production workspace image loader. The image test was also re-run with a valid PNG and an assertion that the browser actually decoded it.
  • pnpm run check:web — passed, including types and appearance/theme checks. pnpm --dir src/web-ui exec tsc --noEmit was re-run after the final production changes and passed.
  • git diff --check — passed.

Earlier validation of the original document-editing implementation:

  • pnpm run i18n:audit — passed with no warnings.
  • pnpm run check:repo-hygiene — passed.
  • pnpm run build:web — passed before the rebase onto upstream/1.0.0-explore at 11788537f.
  • OPENBITFUN_E2E_WEBDRIVER_PORT=4447 E2E_LOG_LEVEL=warn pnpm --dir tests/e2e exec wdio run ./config/wdio.markdown-native.ts — 2 tests passed before the rebase, covering actual desktop WebView editing, dirty markers, production Tauri save, close/reopen, and exact disk content.

Native desktop integration was not re-run for the latest fixes. Remote workspace, Remote Connect, Peer Device Mode, and Detached Dispatch were not exercised.

Reviewer Notes

The native runner uses packaged frontend assets, an isolated temporary application profile, and a temporary workspace. Browser fixtures replace only the filesystem boundary and are not production entrypoints.

Existing appearance mode values remain accepted for compatibility. File access and synchronization continue through existing infrastructure adapters; there are no persisted-format, Tauri-command, or remote-protocol changes.

The latest fixes were exercised in the local browser. Earlier native desktop coverage is recorded separately above; it does not establish remote behavior.

Checklist

  • This PR is focused and does not include secrets, temporary prompts, generated scratch files, or unrelated artifacts.
  • Relevant verification is recorded above, or skipped checks are explained.
  • User-facing strings, docs, and locales are updated where applicable.

@wgqqqqq wgqqqqq left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

审阅发现两个 P2 问题,均已在真实 Chrome 中补充复现,建议修复后合并。现有 82 个定向单测和 8 个浏览器 E2E 全部通过,但未覆盖这两个边界。本次未验证原生桌面、Remote Workspace、Remote Connect、Peer Device Mode 或 Detached Dispatch。

const resolvedSrc = src && isLocalPath(src)
? getCachedLocalImageDataUrl(resolveImagePath(src, this.options.basePath)) ?? src
: src;
if (image.getAttribute('src') !== resolvedSrc) image.setAttribute('src', resolvedSrc);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] 源地址变化时重置本地图片加载状态

此处复用同一个 img 并更新 src,但保留了旧的 data-local-resolved="true",而 resolveEditorLocalImages 会直接跳过带该标记的图片。Chrome 中复现:打开 ![test](https://example.com/old.png),通过图片属性编辑器把地址改成 ./new.png;结果 DOM 为 <img src="./new.png" data-local-resolved="true">,workspaceAPI.readFileContent 没有被调用。新地址因此被当作浏览器相对 URL,无法通过工作区文件接口加载;修改为尚未缓存的另一本地图片也会遇到同样的问题。建议跟踪原始 src,在它变化时清理旧的解析状态并重新走现有图片加载流程,同时补充修改 src 的回归测试。

const end = getNodeEndOffset(child);
if (start !== null && end !== null) {
content.push(withBlockAttrs(
createRenderOnlyBlock(markdown.slice(start, end), child.type ?? 'markdown'),

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] 为脚注块保留全文引用上下文

这里把含脚注引用的段落和脚注定义分别转换为独立的 source-backed block,后续每个块只把自己的 Markdown 交给独立的 MarkdownRenderer,引用和定义便无法互相解析。Chrome 中用 `# Notes

Text1.

Footnotes

  1. Definition复现:原 Preview 显示脚注编号、Definition 正文和返回链接;新文档模式显示字面量Text1.与1: Definition,且 [data-footnote-ref]` 数量为 0。源码虽然保留,原有阅读和导航行为却退化了。建议在块渲染时共享所需的引用定义上下文,并增加实际渲染断言;现有测试只验证定义仍在保存结果中,未覆盖此问题。 ↩ ↩2 ↩3

@wgqqqqq
wgqqqqq merged commit 3ae65ff into GCWing:1.0.0-explore Sep 5, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant