Skip to content

upstream取り込み: v2 file editor foundation (#3526 前半)#310

Merged
MocA-Love merged 1 commit intomainfrom
upstream-merge/pr4-v2-editor-foundation
Apr 17, 2026
Merged

upstream取り込み: v2 file editor foundation (#3526 前半)#310
MocA-Love merged 1 commit intomainfrom
upstream-merge/pr4-v2-editor-foundation

Conversation

@MocA-Love
Copy link
Copy Markdown
Owner

概要

upstream c504a5036 feat(desktop): v2 file editor — foundation, views, and stability pass (#3526)前半 = 未配線の新規土台 を path-checkout で取り込む PR です。c504 の 78 files のうち 58 files を PR4 に、残り 20 files は PR5 で fork adaptation 必要のため defer。behind 4 → 3(c504後半残)。

取り込み内容(新規のみ、既存 wiring は touch しない)

  • apps/desktop/package.json: `@replit/codemirror-css-color-picker` 追加のみ(fork-only dep drop は適用せず)
  • bun.lock: 対応 diff
  • packages/workspace-client/src/providers/WorkspaceClientProvider/WorkspaceClientProvider.tsx: `trpcClient` を context に追加
  • apps/desktop/src/shared/themes/index.ts: `withAlpha` export 追加
  • v2-workspace/\$workspaceId/state/fileDocumentStore/**: 共有ドキュメントストア + provider + hook(新規)
  • FilePane/registry/**: view registry(CodeView / MarkdownPreviewView / ImageView / BinaryWarningView)+ CodeMirror editor stack
  • FilePane/components/{ErrorState,FilePaneHeaderExtras,FileViewToggle,LoadingState,OrphanedBanner,SaveErrorBanner}/**: chrome building blocks
  • types.ts: `FilePaneData` に `viewId?` / `forceViewId?` を optional 追加のみ(`hasChanges` / `displayName` 維持)
  • plans 2本(upstream ドキュメント)

fork 適応 / 除外したもの(PR5 に defer)

以下は fork 独自領域との衝突があるため、PR4 では適用せず PR5 で手動移植予定:

  1. `apps/desktop/src/shared/themes/editor-theme.ts` の token 削除(docComment/controlKeyword/storageKeyword/escape/variableProperty/annotation/markdown*)→ fork 独自 `shiki-theme.ts`(upstream-absent)が参照中
  2. `apps/desktop/package.json` の fork-only dep drop: `@xyflow/react`, `elkjs`, `exceljs`, `ansi_up`, `cron-parser`, `cronstrue`, `diff`, `dockerfile-*`, `@codemirror/merge`, `@taplo/lib`, `@superset/macos-window-blur` → fork 使用中
  3. `hooks/host-service/useFileDocument/**` の削除 → 既存 code 参照中、新 registry 配線後
  4. `FilePane/renderers/**` の削除 → 同上
  5. `FilePane.tsx` / `usePaneRegistry.tsx` / `page.tsx` / `useWorkspaceHotkeys.ts` / `useDefaultContextMenuActions.tsx` → SpreadsheetViewer / displayName / addMemoTab / SEARCH_IN_FILES / BROWSER_RELOAD / reloadToken 等と正面衝突
  6. `hotkeys/registry.ts` の CLOSE_TERMINAL → CLOSE_PANE rename → fork 独自 hotkey 追加と交互作用
  7. `useCopyToClipboard.ts` / `PathActionsMenuItems.tsx` → runtime 挙動変更、別出し検討

検証

  • typecheck: 全26タスク pass(fork tsconfig 完全版)
  • lint: 3件(main baseline と同じ pre-existing、regression なし)
  • 実動: 新規コードは未配線で起動時影響は `trpcClient` context 値追加と `withAlpha` export 追加のみ

Codex pre-review

Yes(全5項目):

  1. 新規土台は import 解決・型整合で自立
  2. `viewId?`/`forceViewId?` は additive、fork の `hasChanges`/`displayName` 経路と無衝突
  3. `trpcClient` 追加は既存 consumer を壊さない(外部実装なし確認済)
  4. 新規 registry/store 側から fork 独自領域への参照なし(孤立)
  5. silent regression リスク低(未配線、実運用経路から未参照)

テストチェックリスト

  • bun install が通る
  • desktop 起動して v2-workspace が現在動作と同じ見た目・動作(新 file editor は未配線)
  • 既存 FilePane の spreadsheet/code/image/markdown レンダリングが従来通り

…-sh#3526)

Cherry-pick PR4 slice of upstream c504a50. Scoped to the foundation
layer only so existing v2 code continues to work unchanged; the
registry/store is not wired yet. PR5 will do the FilePane / page.tsx /
useWorkspaceHotkeys / useDefaultContextMenuActions adaptation.

Scope:
- Add @replit/codemirror-css-color-picker dep (CodeEditor CSS swatches)
- Add `trpcClient` to WorkspaceClientContextValue so the store can
  acquire per-document tRPC handles
- Export `withAlpha` from shared/themes (consumed by editor theme)
- New v2 file editor subsystem (unwired):
  - state/fileDocumentStore/** — shared document store + provider + hook
  - hooks/usePaneRegistry/components/FilePane/registry/** — view
    registry (CodeView / MarkdownPreviewView / ImageView /
    BinaryWarningView) with CodeMirror editor stack
  - hooks/usePaneRegistry/components/FilePane/components/{ErrorState,
    FilePaneHeaderExtras, FileViewToggle, LoadingState, OrphanedBanner,
    SaveErrorBanner}/** — chrome building blocks
- Extend FilePaneData with optional `viewId` / `forceViewId` so the
  new chrome can typecheck; existing `hasChanges` / `displayName` and
  BrowserPaneData fork fields are untouched (deferred to PR5)

FORK NOTES:
- upstream apps/desktop/package.json drop of fork-only deps
  (@xyflow/react, elkjs, exceljs, ansi_up, cron-parser, cronstrue,
  diff, dockerfile-*, @codemirror/merge, @taplo/lib,
  @superset/macos-window-blur) is NOT applied here — those deps are
  still in use.
- upstream apps/desktop/src/shared/themes/editor-theme.ts token
  removals (docComment, controlKeyword, storageKeyword, escape,
  variableProperty, annotation, markdown*) are NOT applied here —
  fork's shiki-theme.ts (upstream-absent) reads them. Deferred to PR5
  so editor-theme.ts and shiki-theme.ts can move together.
- upstream's removal of hooks/host-service/useFileDocument/** and the
  old FilePane renderers/ folder is deferred to PR5, once the new
  registry is wired.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 17, 2026

Warning

Rate limit exceeded

@MocA-Love has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 6 minutes and 26 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 6 minutes and 26 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ca5d69db-a9a0-4a43-b857-1c523de28c83

📥 Commits

Reviewing files that changed from the base of the PR and between 1012b71 and 563121a.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (57)
  • apps/desktop/package.json
  • apps/desktop/plans/20260412-file-editor-v2-feature-audit.md
  • apps/desktop/plans/20260412-file-editor-v2-implementation.md
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/components/ErrorState/ErrorState.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/components/ErrorState/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/components/FilePaneHeaderExtras/FilePaneHeaderExtras.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/components/FilePaneHeaderExtras/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/components/FileViewToggle/FileViewToggle.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/components/FileViewToggle/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/components/LoadingState/LoadingState.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/components/LoadingState/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/components/OrphanedBanner/OrphanedBanner.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/components/OrphanedBanner/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/components/SaveErrorBanner/SaveErrorBanner.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/components/SaveErrorBanner/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/allViews.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/resolveViews.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/types.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/utils/resolveActivePaneView/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/utils/resolveActivePaneView/resolveActivePaneView.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/BinaryWarningView/BinaryWarningView.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/BinaryWarningView/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/CodeView/CodeView.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/CodeView/components/CodeEditor/CodeEditor.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/CodeView/components/CodeEditor/CodeEditorAdapter/CodeEditorAdapter.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/CodeView/components/CodeEditor/CodeEditorAdapter/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/CodeView/components/CodeEditor/constants.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/CodeView/components/CodeEditor/createCodeMirrorTheme/createCodeMirrorTheme.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/CodeView/components/CodeEditor/createCodeMirrorTheme/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/CodeView/components/CodeEditor/extensions/contourSelectionLayer/contourSelectionLayer.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/CodeView/components/CodeEditor/extensions/contourSelectionLayer/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/CodeView/components/CodeEditor/extensions/foldChevron/foldChevron.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/CodeView/components/CodeEditor/extensions/foldChevron/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/CodeView/components/CodeEditor/extensions/foldPlaceholder/foldPlaceholder.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/CodeView/components/CodeEditor/extensions/foldPlaceholder/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/CodeView/components/CodeEditor/extensions/selectionClassTogglePlugin/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/CodeView/components/CodeEditor/extensions/selectionClassTogglePlugin/selectionClassTogglePlugin.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/CodeView/components/CodeEditor/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/CodeView/components/CodeEditor/loadLanguageSupport/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/CodeView/components/CodeEditor/loadLanguageSupport/loadLanguageSupport.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/CodeView/components/CodeEditor/loadLanguageSupport/streamLanguages.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/CodeView/components/CodeEditor/syntax-highlighting/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/CodeView/components/CodeEditor/syntax-highlighting/syntax-highlighting.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/CodeView/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/ImageView/ImageView.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/ImageView/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/MarkdownPreviewView/MarkdownPreviewView.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilePane/registry/views/MarkdownPreviewView/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/state/fileDocumentStore/FileDocumentStoreProvider.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/state/fileDocumentStore/fileDocumentStore.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/state/fileDocumentStore/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/state/fileDocumentStore/types.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/state/fileDocumentStore/useSharedFileDocument.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/types.ts
  • apps/desktop/src/shared/themes/index.ts
  • packages/workspace-client/src/providers/WorkspaceClientProvider/WorkspaceClientProvider.tsx
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch upstream-merge/pr4-v2-editor-foundation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 563121a567

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +104 to +106
entry.byteSize = result.byteLength;
entry.orphaned = false;
entry.hasExternalChange = false;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Guard loadEntry against stale async read responses

loadEntry applies the fetched payload to entry unconditionally after await, but this store can trigger overlapping loads (initial acquire, manual reload, and fs:update events). If an older request resolves after a newer one, it overwrites the newer content/revision and clears external-change flags, so the pane can show stale data until another filesystem event arrives. Adding a per-entry request token (or revision check) before mutating state would prevent out-of-order writes.

Useful? React with 👍 / 👎.

Comment on lines +413 to +415
entry.absolutePath = event.absolutePath;
entries.set(key(entry.workspaceId, entry.absolutePath), entry);
notify(entry);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Avoid clobbering tracked entry on rename key collision

The rename path rewrites the map key with entries.set(...) without handling an existing entry at the destination path. If both source and destination files are currently tracked (e.g., rename/move onto an already-open path), this overwrites the destination map entry while its handles remain alive, which desynchronizes ref-counting and later releaseDocument/event routing for that pane. Handle destination collisions explicitly before re-keying to avoid state corruption.

Useful? React with 👍 / 👎.

@MocA-Love MocA-Love merged commit 1bbd3d7 into main Apr 17, 2026
14 checks passed
MocA-Love added a commit that referenced this pull request Apr 17, 2026
Upstream commits processed (cherry-picked, then adapted where needed):

- 07c1ee0 fix(desktop): Cmd+O firing open-in twice on v1 workspace route (superset-sh#3511)
  → PR #302 (with fork tearoff-window adaptation for Cmd+O)
- 4a1f41a chore(deps): upgrade tanstack/db + electric, drop durable-streams patch (superset-sh#3509)
  → PR #303 (fork keeps fstream patch)
- a3df489 feat(desktop): v2 PR checkout via widened checkout procedure (superset-sh#3525)
  → PR #304 (clean)
- c504a50 feat(desktop): v2 file editor — foundation, views, and stability pass (superset-sh#3526)
  → PR #310 (foundation: 58 files path-checkout)
  → PR #311 (adaptation: 20 files manual port with SpreadsheetViewer/memo/fork-hotkeys preserved)
- 78b7dc8 feat(desktop): promote "Create Section Below" to top-level on workspace menu (superset-sh#3537)
  → PR #308

Record merge so upstream/main..main shows 0 behind.
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