Skip to content

feat: progressive project tree view during import#982

Merged
chagong merged 8 commits intomainfrom
progressive-project-loading
Mar 30, 2026
Merged

feat: progressive project tree view during import#982
chagong merged 8 commits intomainfrom
progressive-project-loading

Conversation

@chagong
Copy link
Copy Markdown
Contributor

@chagong chagong commented Mar 27, 2026

Summary

Show Java project names in the JAVA PROJECTS tree view progressively as they are imported, instead of waiting for the entire import to complete. This reduces perceived loading time for large projects (e.g., 436 Gradle subprojects) from ~7 minutes to ~1 minute.

Problem

For large Gradle projects, the JDTLS import takes 6-7 minutes. During this time, the JAVA PROJECTS tree view is completely empty because:

  1. serverReady() doesn't resolve until import completes
  2. Even if we wait for serverRunning(), the server is blocked by Eclipse workspace locks and can't respond to queries like java.project.list

Solution

Instead of querying the server for project data, create tree nodes directly from ProjectsImported notification URIs sent progressively by JDTLS during import.

Key Changes

languageServerApiManager.ts

  • Use serverRunning() (API >= 0.14) instead of serverReady() so the tree view can start rendering before import finishes
  • Route onDidProjectsImport events to addProgressiveProjects() instead of refresh (which would query the blocked server)
  • Route onDidClasspathUpdate during import to addProgressiveProjects() (non-destructive)
  • After import completes (serverReady()), trigger full refresh to replace placeholders with real data
  • Added isFullyReady() method

dependencyDataProvider.ts

  • Added addProgressiveProjects() — creates ProjectNode items from URIs without server queries
  • Guard getChildren() from entering getRootNodes() during progressive loading (prevents blocking on server queries that hang for the entire import)
  • Keep TreeView progress spinner visible until first progressive items arrive via a deferred promise

commands.ts

  • Added VIEW_PACKAGE_INTERNAL_ADD_PROJECTS command constant

Context

This is part of a 3-repo change for progressive project loading:

  1. feat: progressive project import notifications for tree view eclipse-jdtls/eclipse.jdt.ls#3744 — Server-side progressive notifications
  2. feat: add serverRunning() API (v0.14) for progressive loading redhat-developer/vscode-java#4372serverRunning() API (v0.14)
  3. This PR — Client-side progressive tree view rendering

Testing

Tested with spring-boot project (436 Gradle subprojects):

  • Before: Tree view empty for ~7 minutes until import completes
  • After: 436 project names appear within ~1 minute of opening, with progress spinner showing until items arrive
  • Works both with cached workspace (instant) and after "Clean Java Language Server Workspace" (progressive)
  • After import completes, full refresh replaces placeholder items with proper expandable project nodes

Show Java project names in the tree view progressively as they are
imported, instead of waiting for the entire import to complete.

Key changes:
- Use serverRunning() API (v0.14) instead of serverReady() so the
  tree view can start rendering before import finishes
- Add addProgressiveProjects() to create ProjectNode items directly
  from ProjectsImported notification URIs without querying the server
- Guard getChildren() from entering getRootNodes() during progressive
  loading to avoid blocking on server queries
- Keep TreeView progress spinner visible until first items arrive
- After import completes, trigger full refresh to replace placeholder
  items with complete data from the server

This reduces perceived loading time for large projects (e.g., 436
Gradle subprojects) from ~7 minutes to ~1 minute.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds progressive population of the JAVA PROJECTS tree during JDTLS import by consuming ProjectsImported notifications, so users see project names earlier instead of waiting for full import completion.

Changes:

  • Introduces progressive root project nodes in DependencyDataProvider and avoids root server queries while import is ongoing.
  • Updates LanguageServerApiManager.ready() to use serverRunning() (when available) and wires import/classpath events to progressively add projects, followed by a full refresh after serverReady().
  • Adds an internal command for progressively adding projects to the tree view.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 7 comments.

File Description
src/views/dependencyDataProvider.ts Adds progressive root node population and spinner/await logic during import.
src/languageServerApi/languageServerApiManager.ts Switches readiness behavior to serverRunning() and routes JDTLS events to progressive updates + final refresh.
src/commands.ts Adds internal command ID for progressive project insertion.
package-lock.json Bumps package version metadata to 0.27.1.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

chagong added 2 commits March 30, 2026 10:45
- Extract startServerReadyWait() and call it unconditionally in
  initializeJavaLanguageServerApis() so isServerReady is set correctly
  even if onDidProjectsImport fires before ready() (fixes #6)
- Restore ready() to not start serverReady() wait inline, keeping its
  semantics consistent for other callers like syncHandler,
  upgradeManager, BuildArtifactTaskProvider (fixes #4)
- Add .catch() on serverReady().then() to avoid unhandled promise
  rejections if the server fails to start (fixes #5)
- Restore debounce=true on onDidClasspathUpdate when server is ready
  to avoid burst refreshes (fixes #7)
- Add 30s timeout on _progressiveItemsReady await to prevent
  getChildren() from hanging indefinitely (fixes #2)
- Resolve _progressiveItemsReady in doRefresh() to prevent stale
  getChildren() calls from hanging
After the 30s timeout, if no progressive notifications were received
(e.g., eclipse.jdt.ls progressive notifications not yet available),
fall through to the normal getRootNodes() path instead of returning
an empty array. This ensures the worst case matches today's behavior.

Addresses review comment from wenytang-ms.
wenytang-ms
wenytang-ms previously approved these changes Mar 30, 2026
@chagong chagong merged commit ff3671a into main Mar 30, 2026
5 of 6 checks passed
@chagong chagong deleted the progressive-project-loading branch March 30, 2026 11:39
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.

3 participants