Skip to content

feat(history): group table undo actions and keep silent loads out of history - #364

Open
ruike123xxx wants to merge 2 commits into
floatboatai:mainfrom
ruike123xxx:feat/history-undo-grouping
Open

ruike123xxx wants to merge 2 commits into
floatboatai:mainfrom
ruike123xxx:feat/history-undo-grouping

Conversation

@ruike123xxx

Copy link
Copy Markdown

Summary / 摘要

Group live-preview table edits into one undo step per complete action, and keep silent document loads out of the undo stack.

表格 live-preview 按完整动作(格失焦 / 增删行列)各成一条撤销;silent 打开文件不再进入撤销栈。

Motivation / 背景与动机

Roadmap #8 asks for undo/redo grouping and explicitly says to coordinate with tableEditingCount. Three real gaps, no new host API:

Roadmap 第 8 项要求 undo/redo 分组,并点名要协同 tableEditingCount。三个真实缺口,不加新的宿主 API:

  1. Table widget edits joined typing or each other. Cell commits and add/remove row/column are adjacent document changes. Without isolateHistory, CodeMirror's newGroupDelay merged a table action with nearby typing — one Ctrl+Z reverted both.

    表格操作会和打字并进同一组。 格提交、增删行列都是相邻的文档变更。不加 isolateHistory,CM6 的 newGroupDelay 会把一次表格动作和旁边的打字并掉,一次 Ctrl+Z 两边一起退。

  2. Cell-to-cell navigation cannot dispatch. Existing live-preview tests forbid a blurred cell from stealing focus. So a cell blur that is only moving to another cell must queue the commit (pendingCellCommits) and flush isolated transactions only when leaving the table, while holding the editing lock so CM6 does not recreate the widget mid-flush.

    格子之间不能立刻写回。 已有 live-preview 测试禁止失焦格子抢焦点。格到格的 blur 只能先把提交排进 pendingCellCommits,离开表格后再按格做隔离 dispatch,并且要抓住 editing lock,避免 CM6 在 flush 中途拆掉 widget。

  3. Silent loads and dirty cells polluted history. setDocument(md, { silent: true }) is the file-open path, but it was still recorded as an edit — Ctrl+Z after open reverted the previous buffer. Programmatic undo() / redo() also skipped a cell that had not blurred yet.

    silent 加载和未失焦的格子会污染历史。 setDocument(..., { silent: true }) 是打开文件的路径,却仍被记成一次编辑——打开后立刻 Ctrl+Z 会退回上一份文档。程序化 undo() / redo() 也看不到还没 blur 的格子。

Changes / 变更内容

  • packages/core:
    • src/live-preview-table.ts — tag cell / structure commits with input.table.cell / input.table.structure + isolateHistory.of("full"). Queue per-cell commits on blur; flush them as isolated transactions when leaving the table. Route addRow() through the shared dispatch() so it gets the source-staleness guard.
    • src/editor.ts — silent setDocument / replaceRange use Transaction.addToHistory.of(false). undo() / redo() flush pending table edits before calling CodeMirror.
    • src/types.ts — document that silent also excludes the change from undo history.
  • packages/plugin-history:
    • transactionExtender isolates input.table.* userEvents. No HistoryPluginOptions, no getUndoDepth, no groupHistory. Typing still uses CM6 default joins.
    • Added @codemirror/state (MIT) for Transaction.userEvent / transactionExtender.
  • docs/ROADMAP.md / ROADMAP.zh.md: item feat(core): add getSelectedText() API #8 → in-progress.
  • README.md / README.zh.md: plugin-history line mentions table grouping and silent-load exclusion.
  • apps/electron-demo: —
  • openspec/: —

Testing / 测试

  • Related vitest suites green / 相关用例全绿 — plugin-history 10, editor 48, live-preview 84, live-preview-regressions 9, plugin-toolbar 44, transaction-pipeline 7, dynamic-contributions 10 (212 tests).
  • New / updated vitest cases / 新增或更新的 vitest 用例:
    • packages/plugin-history/test/plugin-history.test.ts — CM6 typing still joins; table cell vs typing isolation; live GFM cell blur undo/redo; adjacent cells after blur are two undos; add-column is one undo; consecutive add-row clicks are two undos; dirty cell + undo() without blur reverts the in-progress edit.
    • packages/core/test/editor.test.ts — silent setDocument / replaceRange stay out of history; non-silent setDocument remains undoable.
  • Manual UI check in electron-demo / electron-demo 手动验证:open a file, Ctrl+Z is a no-op; edit a table cell and leave the table, one undo reverts that cell; add two rows, two undos revert them one at a time.

Compliance / 合规自检

  • CLA signed — will sign via the CLA bot on first PR / 首次 PR 时按 CLA 机器人提示签署
  • AI disclosure: AI pair-programmer (Cursor) drafted implementation and tests; every line was reviewed against the table-widget rules in CLAUDE.md and the existing “blur must not steal focus” contract. No new host API. Design is defensible: isolate by userEvent, queue commits when cell-to-cell navigation cannot dispatch, exclude silent loads with addToHistory: false.
    AI-assisted notes / AI 使用说明:AI 结对起草实现与测试;逐行对照表格 12 条规则和已有失焦测试。未新增宿主 API。
  • New dependencies (if any) listed with license & rationale:
    • @codemirror/state@^6.6.0 — MIT — Transaction.userEvent / transactionExtender in plugin-history; already used by sibling packages.
  • No build artifacts committed / 未提交构建产物
  • No secrets / .env / personal vault data committed / 无敏感信息

Checklist / 自检清单

  • Title follows Conventional Commits / 标题遵循 Conventional Commits
  • Public API changes update package README / types — silent history exclusion documented on setDocument / replaceRange; no new methods
  • Touched live-preview-table.ts → walked through the 12 Table Widget rules in CLAUDE.md / 已核对 12 条表格规则 — cell-to-cell still skips dispatch; tableEditingCount held across queued flush; addRow uses shared dispatch; no HTML5 drag; no inline border styles
  • New capability / breaking change → OpenSpec proposal linked / 无新 capability,Roadmap 标明不需要 OpenSpec
  • Change aligns with project scope (GOVERNANCE.md §4) / 改动符合 GOVERNANCE.md §4 的项目范围

ruike123xxx and others added 2 commits September 21, 2026 17:57
Keep CM6 typing joins, isolate table actions, and split pending cell commits so Ctrl+Z matches one complete table action.

Co-authored-by: Cursor <cursoragent@cursor.com>
Silent setDocument was still recorded as an edit, so Ctrl+Z after opening a file reverted the previous buffer. Undo also skipped in-progress table cells that had not blurred yet.

Co-authored-by: Cursor <cursoragent@cursor.com>
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

This branch has not been deployed

No deployments
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.

2 participants