Skip to content

fix(preview): catch CodeMirror mapPos RangeError in editors (ELECTRON-3Y)#1940

Merged
piorpua merged 1 commit intomainfrom
fix/sentry-ELECTRON-3Y
Mar 30, 2026
Merged

fix(preview): catch CodeMirror mapPos RangeError in editors (ELECTRON-3Y)#1940
piorpua merged 1 commit intomainfrom
fix/sentry-ELECTRON-3Y

Conversation

@kaizhou-lab
Copy link
Copy Markdown
Collaborator

@kaizhou-lab kaizhou-lab commented Mar 30, 2026

Summary

Fixes ELECTRON-3YRangeError: Position X is out of range for changeset of length Y in ChangeDesc.mapPos (6 events, last seen 6 hours ago, still active).

Root cause: When the active tab changes in PreviewPanel, CodeMirror editors receive a completely new value prop. Without a key tied to the tab ID, React reuses the same component instance and @uiw/react-codemirror tries to reconcile the old internal state with the new value via ChangeDesc.mapPos(), which throws when stale positions exceed the new document length.

Additionally, InlineAgentEditor's handleJsonChange had overlapping setTimeout calls that could prematurely clear the editing flag, allowing useEffect to overwrite CodeMirror's value mid-edit.

Fix:

  • Add key={activeTabId} to all CodeMirror editor instances in PreviewPanel.tsx — forces React to unmount/remount the editor on tab switch, preventing stale position errors entirely
  • Fix timer race condition in InlineAgentEditor.tsx — clear previous timer before setting a new one

Test plan

  • New unit test previewEditorKeyRemount.test.ts verifies timer cleanup prevents premature flag reset
  • Full test suite passes (210/211 — 1 pre-existing failure in previewFileWatch.dom.test.ts)
  • bunx tsc --noEmit passes
  • bun run lint:fix passes (0 errors)
  • bun run format passes

@kaizhou-lab kaizhou-lab marked this pull request as ready for review March 30, 2026 10:16
…SON edits (ELECTRON-3Y)

Add key={activeTabId} to all CodeMirror editor instances in PreviewPanel
to force React to remount the editor when switching tabs, preventing
stale position errors from in-place value reconciliation.

Also fix a timer race condition in InlineAgentEditor's handleJsonChange
where overlapping setTimeout calls could prematurely clear the editing
flag, allowing the useEffect to overwrite CodeMirror's value mid-edit.
@kaizhou-lab kaizhou-lab force-pushed the fix/sentry-ELECTRON-3Y branch from 7a8d98e to 921f972 Compare March 30, 2026 10:31
@piorpua piorpua added the bot:reviewing Review in progress (mutex) label Mar 30, 2026
@piorpua
Copy link
Copy Markdown
Contributor

piorpua commented Mar 30, 2026

Code Review:fix(preview): catch CodeMirror mapPos RangeError in editors (ELECTRON-3Y) (#1940)

变更概述

本 PR 修复了两个独立问题:① PreviewPanel 切换标签页时,CodeMirror 编辑器实例(MarkdownEditor、HTMLEditor、TextEditor)因 React 复用旧实例而产生 ChangeDesc.mapPos RangeError;② InlineAgentEditor 中 handleJsonChangesetTimeout 存在竞态,可能导致 isJsonEditingRef 被过早重置。改动涉及 renderer 进程的两个 UI 组件及一个新增单元测试文件。


方案评估

结论:✅ 方案合理

两处修复均直接针对根因:给编辑器加 key 是 React 官方推荐的强制重挂载方式,比在 useEffect 里手动同步 EditorView 更简洁可靠;用 ref 管理 timer 并在覆盖前清除是修复 debounce 竞态的标准做法。方案没有引入额外抽象,与项目现有代码风格一致。


问题清单

🔵 LOW — activeTabId ?? undefined 冗余

文件PreviewPanel.tsx,第 440、512、552、597、620 行

修复建议key={activeTabId} — React 对 key={null}key={undefined} 处理完全相同,?? undefined 无实际效果。


🔵 LOW — 第三个测试用例不验证任何行为

文件tests/unit/previewEditorKeyRemount.test.ts,第 87–99 行

第三个用例仅断言两个字面量字符串不相等,无论修复是否正确都必然通过,对回归保护没有贡献。建议删除或替换为真实的组件行为验证。


汇总

# 严重级别 文件 问题
1 🔵 LOW PreviewPanel.tsx:440,512,552,597,620 ?? undefined 冗余表达式
2 🔵 LOW previewEditorKeyRemount.test.ts:87 第三个测试用例无实质断言

结论

批准合并 — 无阻塞性问题,两处修复方向正确,仅有两个低优先级建议供参考。


本报告由本地 pr-review skill 生成,包含完整项目上下文,无截断限制。

CONCLUSION: APPROVED
IS_CRITICAL_PATH: false
PR_NUMBER: 1940

@piorpua
Copy link
Copy Markdown
Contributor

piorpua commented Mar 30, 2026

✅ 已自动 review,无阻塞性问题,正在触发自动合并。

@piorpua piorpua added bot:ready-to-merge Bot done, code is clean — human just needs to confirm and merge and removed bot:reviewing Review in progress (mutex) labels Mar 30, 2026
@piorpua
Copy link
Copy Markdown
Contributor

piorpua commented Mar 30, 2026

⚠️ 自动合并触发失败(auto-merge 未成功启用),已标记 bot:ready-to-merge,请人工确认后合并。

@piorpua piorpua merged commit 7da5ccc into main Mar 30, 2026
19 of 30 checks passed
@piorpua piorpua deleted the fix/sentry-ELECTRON-3Y branch March 30, 2026 12:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot:ready-to-merge Bot done, code is clean — human just needs to confirm and merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants