Skip to content

fix: stop multi-root/huge-workspace hang and crash (#7)#8

Merged
mnismt merged 1 commit into
mainfrom
fix/issue-7-workspace-hang-lazy-tree
May 31, 2026
Merged

fix: stop multi-root/huge-workspace hang and crash (#7)#8
mnismt merged 1 commit into
mainfrom
fix/issue-7-workspace-hang-lazy-tree

Conversation

@mnismt

@mnismt mnismt commented May 31, 2026

Copy link
Copy Markdown
Owner

Fixes #7.

Problem

Opening the panel scanned every workspace root recursively, sent the whole tree in one postMessage, and rendered every node regardless of collapse state — OOM on large/multi-root workspaces.

Changes

  • Lazy load: getWorkspaceRoots (shallow) + getDirectoryChildren on expand; children merged into tree state
  • Collapse-gated rendering (children render only when expanded)
  • Default heavy-dir excludes (node_modules, dist, build, .next, ...) + async gitignore I/O
  • Scan caps (depth/nodes/list) + AbortSignal + 30s timeout + coalesced getFileTree
  • Select-all via listFilesUnderUri; copyContext via generateFileMapFromSelections (no full-tree cache)
  • Iterative getAllDescendantPaths; truncation banner

Bugs fixed (not caught by old tests — they only used a populated mock tree)

  • buildTreeIndex threw on shallow folders (subItems undefined) → guarded with subItems ?? []
  • Seeded-expanded roots never fetched children on load/refresh → auto-load expanded-but-unloaded roots (guarded by loadingFolderUris)

Tests

  • Backend file-system.test.ts: excludes/gitignore/abort/shallow roots (workspace cases self-skip if workspaceFolders can't be stubbed)
  • Webview: shallow-root auto-load, no double-request, no reload of loaded roots, buildTreeIndex shallow coverage

Verified

check-types, tsc -p . --outDir out, biome check src clean; pnpm -C src/webview-ui test --run → 119 passed.

Not run here (confirm in CI/local)

pnpm test (electron host); manual multi-root .code-workspace repro.

Known limitations

  • Select-all on a collapsed folder adds files but the badge stays none/partial until expanded (counts reflect loaded nodes only)
  • Search matches loaded folders only (banner shown)

Opening the panel previously scanned every workspace root recursively,
shipped the whole tree in one postMessage, and rendered every node
regardless of collapse state — OOMing the host/webview on large or
multi-root workspaces.

Backend (extension):
- Lazy APIs: getWorkspaceRoots (shallow), getDirectoryChildren,
  listFilesUnderUri; getWorkspaceFileTree kept (capped) for legacy/tests
- Default heavy-dir excludes (node_modules, dist, build, .next, ...)
- Async gitignore I/O via loadIgnoreRulesForRoot
- Scan caps (depth/nodes/list) + AbortSignal + coalesced getFileTree
- copyContext uses generateFileMapFromSelections (no full-tree cache)

Webview:
- Collapse-gated render; only expanded folders render children
- Lazy expand fetches children via getDirectoryChildren and merges them
- Select-all uses extension listFilesUnderUri; truncation banner
- Iterative getAllDescendantPaths

Fixes found while validating:
- buildTreeIndex crashed on shallow (unloaded) folders whose subItems
  is undefined — guard with `subItems ?? []`
- Seeded-expanded roots never fetched children on first render/refresh —
  auto-load expanded-but-unloaded roots (guarded by loadingFolderUris)

Tests:
- Backend file-system.test.ts: excludes/gitignore/abort/shallow roots
  (workspace-scoped cases self-skip if workspaceFolders can't be stubbed)
- Webview: shallow-root auto-load, no double-request, no auto-load of
  already-loaded roots; buildTreeIndex shallow-folder coverage

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mnismt mnismt merged commit 62b6f14 into main May 31, 2026
4 checks passed
@mnismt mnismt deleted the fix/issue-7-workspace-hang-lazy-tree branch May 31, 2026 08:25
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.

Throw VSCODE when open plugin with workspace folder

1 participant