Skip to content

IEP-1754 Run ESP-IDF version detection asynchronously with progress reporting#1445

Merged
kolipakakondal merged 2 commits into
masterfrom
IEP-1754
Apr 28, 2026
Merged

IEP-1754 Run ESP-IDF version detection asynchronously with progress reporting#1445
kolipakakondal merged 2 commits into
masterfrom
IEP-1754

Conversation

@sigmaaa
Copy link
Copy Markdown
Collaborator

@sigmaaa sigmaaa commented Apr 22, 2026

Description

Currently, the refreshEditorUI method runs the version detection command synchronously for every configured ESP-IDF environment. If a user has multiple environments, this significantly prolongs the refresh process and freezes the Eclipse UI.

Fix: Offload the version detection commands to run concurrently in the background using Virtual Threads.

Wrapped the process in an Eclipse Job so the UI remains completely responsive, and the user sees a progress monitor.

Fixes # (IEP-1754)

Type of change

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)

How has this been tested?

Install multiple ESP-IDF versions → open the ESP-IDF Manager and track how long it takes to display all ESP-IDF versions.

Test Configuration:

  • ESP-IDF Version:
  • OS (Windows,Linux and macOS):

Dependent components impacted by this PR:

  • Esp-idf manager

Checklist

  • PR Self Reviewed
  • Applied Code formatting
  • Added Documentation
  • Added Unit Test
  • Verified on all platforms - Windows,Linux and macOS

Summary by CodeRabbit

  • Refactor
    • Optimized table update performance with enhanced asynchronous processing using virtual threading for improved responsiveness
    • Added detailed progress reporting during long-running operations
    • Strengthened error handling with improved exception reporting during refresh cycles

@sigmaaa sigmaaa self-assigned this Apr 22, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 22, 2026

📝 Walkthrough

Walkthrough

Replaced CompletableFuture-based refresh with an Eclipse Job that reports progress via IProgressMonitor, computes per-IDF rows using a VirtualThreadPerTaskExecutor, moves UI updates into a single Display.asyncExec block, changes exception handling to in-job try/catch returning IStatus, and removed the stored toolInitializer field and EIM JSON refresh.

Changes

Cohort / File(s) Summary
Main page refactor
bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java
Replaced CompletableFuture pipeline with an Eclipse Job returning IStatus and using IProgressMonitor; per-IDF row computation moved into the job with a VirtualThreadPerTaskExecutor and per-IDF CompletableFutures joined before UI update; UI updates (input/selection preservation, resetting install state, updateButtonState()) moved to a single Display.asyncExec(); exceptions caught and logged in-job; removed updating eimJson during refresh; removed toolInitializer field and instantiate it without storing.
Localization additions
bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/Messages.java
Added four new public message keys for ESPIDFMainTablePage (detecting subtask, refresh failure, refreshing job name, scanning task name).
i18n properties
bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/messages.properties
Added corresponding message strings for detecting ESP-IDF, refresh failure, refreshing environments job name, and scanning configurations task name.

Sequence Diagram(s)

sequenceDiagram
  participant UI as "UI / Display"
  participant Job as "Eclipse Job"
  participant Executor as "VirtualThreadPerTaskExecutor"
  participant Task as "Per-IDF Task"
  participant Model as "Table Model"

  UI->>Job: schedule(refresh)
  Job->>Job: run(IProgressMonitor)
  Job->>Executor: submit per-IDF tasks
  Executor->>Task: start detection (parallel)
  Task-->>Executor: row data (future)
  Executor->>Job: join all futures -> rows
  Job->>Model: set new input (background)
  Job->>UI: asyncExec(update input/selection, reset install node, updateButtonState)
  UI-->>Job: UI updated
  Job-->>UI: return IStatus (OK/ERROR)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • kolipakakondal
  • AndriiFilippov
  • alirana01

Poem

🐰 I hopped from futures into Jobs so bright,
Spun virtual threads across the night,
Rows assembled, joined in line,
UI naps then wakes — all fine! ✨
A twitch, a hop, and clean new light.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: converting async ESP-IDF version detection to use Eclipse Jobs with progress reporting and asynchronous execution.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch IEP-1754

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

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java (1)

96-96: Remove or retain the ToolInitializer intentionally.

This instance is immediately discarded, and the referenced constructor only initializes instance fields, so this line currently has no observable effect. Either remove it or restore a field if later logic should use ToolInitializer.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java`
at line 96, The ToolInitializer instance created on its own in
ESPIDFMainTablePage (new
ToolInitializer(InstanceScope.INSTANCE.getNode(UIPlugin.PLUGIN_ID))) has no
effect because it is immediately discarded; either remove that statement
entirely or persist the instance to a field (e.g., add a private final
ToolInitializer toolInitializer and assign it in the constructor) so the
initializer's state is retained and can be used later; update the class
constructor and any references to use toolInitializer if kept, otherwise simply
delete the line to avoid a no-op side effect.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java`:
- Around line 438-467: Rows are built from the local newJson but the shared
field eimJson remains stale, causing performToolsSetup() (and SetupToolsInIde
construction) to operate on old data; inside the
Display.getDefault().asyncExec(...) block, assign the freshly parsed newJson to
the eimJson field (e.g., eimJson = newJson) before calling
tableViewer.setInput(finalRows) or any code that may trigger
performToolsSetup()/new SetupToolsInIde, ensuring UI-thread synchronization of
the configuration state.
- Around line 478-480: The finally block formatting must follow the project
brace style: move the `finally` keyword to its own line so the closing brace of
the try/catch ends on one line and `finally` begins the next, e.g. change the
sequence that currently reads like `} finally {` (around the block that calls
`monitor.done()`) to `}\nfinally\n{`, ensuring the block that contains
`monitor.done()` retains its contents unchanged.

---

Nitpick comments:
In
`@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java`:
- Line 96: The ToolInitializer instance created on its own in
ESPIDFMainTablePage (new
ToolInitializer(InstanceScope.INSTANCE.getNode(UIPlugin.PLUGIN_ID))) has no
effect because it is immediately discarded; either remove that statement
entirely or persist the instance to a field (e.g., add a private final
ToolInitializer toolInitializer and assign it in the constructor) so the
initializer's state is retained and can be used later; update the class
constructor and any references to use toolInitializer if kept, otherwise simply
delete the line to avoid a no-op side effect.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bf0b69c2-08c1-44a1-9f5f-a41a750edc3e

📥 Commits

Reviewing files that changed from the base of the PR and between 6a67e13 and 9b18216.

📒 Files selected for processing (1)
  • bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java

Comment on lines +438 to +467
var newJson = configParser.getEimJson(true);
List<IdfRow> rows = List.of();

if (newJson != null && newJson.getIdfInstalled() != null)
{
var gitPath = newJson.getGitPath();

monitor.subTask("Detecting ESP-IDF versions...");

try (var executor = Executors.newVirtualThreadPerTaskExecutor())
{
var futures = newJson.getIdfInstalled().stream().map(idf -> CompletableFuture.supplyAsync(
() -> new IdfRow(idf, ToolsUtility.isIdfInstalledActive(idf),
ToolsUtility.getIdfVersion(idf, gitPath), idf.getName(), idf.getPath()),
executor)).toList();

rows = futures.stream().map(CompletableFuture::join).toList();
}
}

final List<IdfRow> finalRows = rows;

Display.getDefault().asyncExec(() -> {
if (container.isDisposed())
return;

var currentSelection = tableViewer.getSelection();
currentInstallingNode = null;

tableViewer.setInput(finalRows);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Keep eimJson synchronized with the refreshed configuration.

Rows are rebuilt from newJson, but performToolsSetup() still uses the stale eimJson field when creating SetupToolsInIde. Refresh the field on the UI thread before exposing the new rows.

🐛 Proposed fix
 					var newJson = configParser.getEimJson(true);
 					List<IdfRow> rows = List.of();
@@
 					}
 
+					final EimJson finalJson = newJson;
 					final List<IdfRow> finalRows = rows;
 
 					Display.getDefault().asyncExec(() -> {
 						if (container.isDisposed())
 							return;
 
 						var currentSelection = tableViewer.getSelection();
+						this.eimJson = finalJson;
 						currentInstallingNode = null;
 
 						tableViewer.setInput(finalRows);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java`
around lines 438 - 467, Rows are built from the local newJson but the shared
field eimJson remains stale, causing performToolsSetup() (and SetupToolsInIde
construction) to operate on old data; inside the
Display.getDefault().asyncExec(...) block, assign the freshly parsed newJson to
the eimJson field (e.g., eimJson = newJson) before calling
tableViewer.setInput(finalRows) or any code that may trigger
performToolsSetup()/new SetupToolsInIde, ensuring UI-thread synchronization of
the configuration state.

Comment on lines +478 to +480
} finally
{
monitor.done();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Match the project brace style for finally.

The repository formatter requires block braces on the next line; split finally from the preceding closing brace. As per coding guidelines, “Place opening brace on the next line for types, methods, constructors, blocks, and switch statements.”

🎨 Proposed formatting fix
-				} finally
+				}
+				finally
 				{
 					monitor.done();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} finally
{
monitor.done();
}
finally
{
monitor.done();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java`
around lines 478 - 480, The finally block formatting must follow the project
brace style: move the `finally` keyword to its own line so the closing brace of
the try/catch ends on one line and `finally` begins the next, e.g. change the
sequence that currently reads like `} finally {` (around the block that calls
`monitor.done()`) to `}\nfinally\n{`, ensuring the block that contains
`monitor.done()` retains its contents unchanged.

@sigmaaa sigmaaa changed the title IEP-1754 Run ESP-IDF version detection asynchronously with progress reporting [WIP] IEP-1754 Run ESP-IDF version detection asynchronously with progress reporting Apr 23, 2026
@AndriiFilippov
Copy link
Copy Markdown
Collaborator

@sigmaaa hi !

The original delay on Windows machines was improved.

LGTM 👍

@sigmaaa sigmaaa changed the title [WIP] IEP-1754 Run ESP-IDF version detection asynchronously with progress reporting IEP-1754 Run ESP-IDF version detection asynchronously with progress reporting Apr 27, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (2)
bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java (2)

478-480: ⚠️ Potential issue | 🟡 Minor

Match the project brace style for finally.

finally should start on its own line here to stay formatter-clean.

🎨 Proposed formatting fix
-				} finally
+				}
+				finally
 				{
 					monitor.done();

As per coding guidelines, "Place opening brace on the next line for types, methods, constructors, blocks, and switch statements".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java`
around lines 478 - 480, The finally keyword is not placed on its own line per
project brace style; in the ESPIDFMainTablePage class's finally block move the
`finally` so it appears on its own line and ensure its opening brace is on the
next line (i.e., change the current "} finally {" sequence to "}" then a newline
with "finally" and a newline with "{", leaving the monitor.done() call inside).

438-469: ⚠️ Potential issue | 🟠 Major

Refresh eimJson together with the new rows.

Rows are rebuilt from newJson, but performToolsSetup() still reads the stale field at Line 419. After a refresh, activate/reinstall can run against outdated config.

🐛 Proposed fix
 					var newJson = configParser.getEimJson(true);
 					List<IdfRow> rows = List.of();
@@
-					final List<IdfRow> finalRows = rows;
+					final EimJson finalJson = newJson;
+					final List<IdfRow> finalRows = rows;

 					Display.getDefault().asyncExec(() -> {
 						if (container.isDisposed())
 							return;

 						var currentSelection = tableViewer.getSelection();
+						eimJson = finalJson;
 						currentInstallingNode = null;

 						tableViewer.setInput(finalRows);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java`
around lines 438 - 469, The rows are built from configParser.getEimJson(true)
into local newJson but the shared eimJson used by performToolsSetup() remains
stale; update the shared state by assigning the refreshed newJson to the
instance field (e.g., eimJson) before UI actions so performToolsSetup(),
activate/reinstall handlers, and updateButtonState() see the new config.
Concretely, after creating newJson and before calling
tableViewer.setInput(finalRows) (inside the Display.asyncExec block) set the
instance eimJson = newJson (or call the class method that refreshes it) so all
subsequent code (performToolsSetup(), updateButtonState(), etc.) uses the
refreshed configuration.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In
`@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java`:
- Around line 478-480: The finally keyword is not placed on its own line per
project brace style; in the ESPIDFMainTablePage class's finally block move the
`finally` so it appears on its own line and ensure its opening brace is on the
next line (i.e., change the current "} finally {" sequence to "}" then a newline
with "finally" and a newline with "{", leaving the monitor.done() call inside).
- Around line 438-469: The rows are built from configParser.getEimJson(true)
into local newJson but the shared eimJson used by performToolsSetup() remains
stale; update the shared state by assigning the refreshed newJson to the
instance field (e.g., eimJson) before UI actions so performToolsSetup(),
activate/reinstall handlers, and updateButtonState() see the new config.
Concretely, after creating newJson and before calling
tableViewer.setInput(finalRows) (inside the Display.asyncExec block) set the
instance eimJson = newJson (or call the class method that refreshes it) so all
subsequent code (performToolsSetup(), updateButtonState(), etc.) uses the
refreshed configuration.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 22b8c70b-e7c1-49a7-8a3d-ec2bc02b761c

📥 Commits

Reviewing files that changed from the base of the PR and between 9b18216 and c974b75.

📒 Files selected for processing (3)
  • bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/Messages.java
  • bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java
  • bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/messages.properties
✅ Files skipped from review due to trivial changes (1)
  • bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/messages.properties

@kolipakakondal kolipakakondal added this to the v4.3.0 milestone Apr 28, 2026
Copy link
Copy Markdown
Collaborator

@kolipakakondal kolipakakondal left a comment

Choose a reason for hiding this comment

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

LGTM

@kolipakakondal kolipakakondal merged commit 9b1606f into master Apr 28, 2026
4 of 6 checks passed
@kolipakakondal kolipakakondal deleted the IEP-1754 branch April 28, 2026 06:28
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