Skip to content

Conversation

@kolipakakondal
Copy link
Collaborator

@kolipakakondal kolipakakondal commented Sep 3, 2025

Description

This PR implements dynamic ESP-IDF target discovery that automatically reads both supported and preview targets from ESP-IDF's constants.py file, eliminating the need for manual plugin updates when new targets are added. The solution includes full backward compatibility and handles the toolchain unification

Key Features
Dynamic targets: Automatically discovers all targets from ESP-IDF
Preview targets: Automatically discovers all preview targets
Future-proof: New targets appear without plugin updates going forward when esp-idf supports new targets
Zero maintenance: No manual plugin.xml updates needed
Backward Compatibility: Works with ESP-IDF v5.0+ (both target-specific and unified toolchain structures)

Fixes # (IEP-XXX)

Type of change

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

How has this been tested?

  • Add esp-idf esp-idf version and verify that all the supported targets and preview targets are visible

Test Configuration:

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

Dependent components impacted by this PR:

  • launch configuration
  • build
  • flash
  • debugging

Checklist

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

Summary by CodeRabbit

  • New Features

    • Toolchains and targets are now discovered dynamically from your ESP-IDF installation; project target lists in the UI populate from those discoveries.
  • Bug Fixes

    • Prevented a crash when determining the default board for targets that have no boards defined.
  • Refactor

    • Removed bundled predefined toolchain entries; toolchain loading/activation now relies on ESP-IDF-derived target information.

@coderabbitai
Copy link

coderabbitai bot commented Sep 3, 2025

Walkthrough

Removed static toolchain entries from plugin.xml and replaced registry/extension-based loading with runtime discovery of ESP-IDF targets. Added IDFTargets and IDFTargetsReader to parse targets from ESP-IDF. Updated ESPToolChainManager, ToolsActivationJob, NewProjectCreationWizardPage, and added a guard in DefaultBoardProvider.

Changes

Cohort / File(s) Summary
Remove plugin toolchain extensions
bundles/com.espressif.idf.core/plugin.xml
Deleted the com.espressif.idf.core.toolchain extension block that defined 8 static ToolChain entries (xtensa: esp32, esp32s2, esp32s3; riscv32: esp32c2, esp32c3, esp32c6, esp32h2, esp32p4). Other extensions unchanged.
Dynamic toolchain discovery core
bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/ESPToolChainManager.java
Replaced extension-registry loading with dynamic discovery: reads idfPath via IDFUtil.getIDFPath() and uses IDFTargetsReader.readTargetsFromEspIdf(idfPath) to build ESPToolChainElement instances; removed registry iteration and added runtime logging of loaded count.
IDF targets model and parser
bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/IDFTargets.java
bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/IDFTargetsReader.java
Added IDFTargets model with supported/preview target lists and IDFTarget metadata helpers. Added IDFTargetsReader.readTargetsFromEspIdf(String) which parses tools/idf_py_actions/constants.py to extract SUPPORTED_TARGETS and PREVIEW_TARGETS and populates IDFTargets.
Tool activation / UI flow updates
bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/ToolsActivationJob.java
bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/templates/NewProjectCreationWizardPage.java
Switched target sourcing to IDFTargetsReader.readTargetsFromEspIdf(IDFUtil.getIDFPath()) for tool setup and project-creation UI; removed previous toolset-based extraction/error branch and adapted target list construction.
Default board guard
bundles/com.espressif.idf.core/src/com/espressif/idf/core/DefaultBoardProvider.java
Added guard in getDefaultBoard: when boards array is empty, return EspTarget.enumOf(targetName).board instead of indexing into an empty array.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant UI as ToolsActivationJob
  participant IDF as IDFUtil
  participant Reader as IDFTargetsReader
  participant Targets as IDFTargets
  participant Mgr as ESPToolChainManager

  User->>UI: trigger tools activation
  UI->>IDF: getIDFPath()
  IDF-->>UI: idfPath
  UI->>Reader: readTargetsFromEspIdf(idfPath)
  Reader-->>Targets: parsed targets (supported + preview)
  UI->>Mgr: configureToolChain(targetNames)
  Mgr->>IDF: getIDFPath()
  Mgr->>Reader: readTargetsFromEspIdf(idfPath)
  Reader-->>Mgr: IDFTargets
  Mgr->>Mgr: map IDFTarget -> ESPToolChainElement
  Mgr-->>UI: toolchains configured
  UI-->>User: setup complete
Loading
sequenceDiagram
  autonumber
  participant Mgr as ESPToolChainManager
  participant IDF as IDFUtil
  participant Reader as IDFTargetsReader
  participant Targets as IDFTargets

  Note over Mgr: New dynamic loading flow
  Mgr->>IDF: getIDFPath()
  IDF-->>Mgr: idfPath
  Mgr->>Reader: readTargetsFromEspIdf(idfPath)
  Reader-->>Targets: parse constants.py (SUPPORTED/PREVIEW)
  Reader-->>Mgr: IDFTargets
  Mgr->>Mgr: create ESPToolChainElement for each IDFTarget
  Mgr-->>Mgr: log "Dynamically loaded N toolchain elements"
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • AndriiFilippov
  • sigmaaa

Poem

A rabbit read the constants.py,
Chased targets beneath the IDF sky.
XML carrots left the bed,
Toolchains sprout where Python led.
Boards secure — no index dread! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 45.45% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly captures the primary change by highlighting both dynamic ESP-IDF target discovery and preview target support, reflecting the key functionality introduced in this PR.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch toolchain_refactor

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between feef302 and 3cb1caa.

📒 Files selected for processing (1)
  • bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/IDFTargets.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/IDFTargets.java
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build_windows

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.

@kolipakakondal kolipakakondal changed the title fix: toolchain refactoring and support preview targets WIP: toolchain refactoring and support preview targets Sep 4, 2025
@kolipakakondal kolipakakondal changed the title WIP: toolchain refactoring and support preview targets Dynamic ESP-IDF Target Discovery with Backward Compatibility Sep 18, 2025
@kolipakakondal kolipakakondal marked this pull request as ready for review September 18, 2025 06:58
@kolipakakondal kolipakakondal changed the title Dynamic ESP-IDF Target Discovery with Backward Compatibility Dynamic ESP-IDF Target Discovery and Support Preview Targets Sep 18, 2025
Copy link

@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: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/ToolsActivationJob.java (1)

176-185: Guard against empty/invalid IDF_PATH to avoid destructive cleanup

If IDF_PATH is absent or parsing yields zero targets, this removes all launch targets and toolchains. Add safe guards.

 	private void setUpToolChainsAndTargets()
 	{
-		//Get current active idf
-		String idfPath = IDFUtil.getIDFPath();
-		List<String> targets = IDFTargetsReader.readTargetsFromEspIdf(idfPath).getAllTargetNames();
+		// Get current active idf
+		String idfPath = IDFUtil.getIDFPath();
+		if (StringUtil.isEmpty(idfPath) || !new File(idfPath).exists()) {
+			Logger.log("IDF_PATH is unset or invalid; skipping toolchain reconfiguration to preserve current setup"); //$NON-NLS-1$
+			return;
+		}
+		List<String> targets = IDFTargetsReader.readTargetsFromEspIdf(idfPath).getAllTargetNames();
+		if (targets == null || targets.isEmpty()) {
+			Logger.log("No targets discovered from ESP-IDF; skipping cleanup/configuration to avoid removing existing toolchains"); //$NON-NLS-1$
+			return;
+		}
 
 		ESPToolChainManager espToolChainManager = new ESPToolChainManager();
 		espToolChainManager.removeLaunchTargetsNotPresent(targets);
 		espToolChainManager.removeCmakeToolChains();
 		espToolChainManager.removeStdToolChains();
 		espToolChainManager.configureToolChain(targets);
 	}
🧹 Nitpick comments (5)
bundles/com.espressif.idf.core/src/com/espressif/idf/core/DefaultBoardProvider.java (2)

59-66: Null-safety for boards list before streaming.

If EspConfigParser.getBoardsForTarget can return null, Line 60 will NPE. Guard early and avoid creating an array when empty.

Apply:

-        List<Board> boardsList = this.espConfigParser.getBoardsForTarget(targetName);
-        String[] boards = boardsList.stream().map(Board::name).toArray(String[]::new);
-        
-        if (boards.length == 0)
-        {
-            return EspTarget.enumOf(targetName).board;
-        }
-        
-        return boards[getIndexOfDefaultBoard(targetName, boards)];
+        List<Board> boardsList = this.espConfigParser.getBoardsForTarget(targetName);
+        if (boardsList == null || boardsList.isEmpty()) {
+            return EspTarget.enumOf(targetName).board;
+        }
+        String[] boards = boardsList.stream().map(Board::name).toArray(String[]::new);
+        return boards[getIndexOfDefaultBoard(targetName, boards)];

23-38: Consider deriving defaults from dynamic target metadata instead of hardcoded enum.

With dynamic ESP-IDF target discovery, hardcoded defaults for only ESP32C3/S3 are fragile for new targets. If feasible, read a “default board” hint alongside targets; otherwise document that unknown targets return an empty string.

Add a TODO to revisit once IDFTargetsReader exposes such metadata.

bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/IDFTargets.java (2)

46-54: Return unmodifiable views to prevent external mutation of internal state

Expose read-only lists to callers to avoid accidental modification.

 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
@@
 	public List<IDFTarget> getSupportedTargets()
 	{
-		return supportedTargets;
+		return Collections.unmodifiableList(supportedTargets);
 	}
@@
 	public List<IDFTarget> getPreviewTargets()
 	{
-		return previewTargets;
+		return Collections.unmodifiableList(previewTargets);
 	}

Also applies to: 51-54


38-44: De-duplicate when combining supported + preview targets

If a target appears in both lists, names and entries will be duplicated. Consider dedup at merge or name extraction.

 	public List<IDFTarget> getAllTargets()
 	{
-		List<IDFTarget> allTargets = new ArrayList<>();
-		allTargets.addAll(supportedTargets);
-		allTargets.addAll(previewTargets);
-		return allTargets;
+		List<IDFTarget> allTargets = new ArrayList<>(supportedTargets.size() + previewTargets.size());
+		allTargets.addAll(supportedTargets);
+		for (IDFTarget t : previewTargets) {
+			if (allTargets.stream().noneMatch(x -> x.getName().equals(t.getName()))) {
+				allTargets.add(t);
+			}
+		}
+		return allTargets;
 	}
@@
 	public List<String> getAllTargetNames()
 	{
-		return getAllTargets().stream().map(IDFTarget::getName).collect(java.util.stream.Collectors.toList());
+		return getAllTargets().stream().map(IDFTarget::getName).distinct()
+				.collect(java.util.stream.Collectors.toList());
 	}

Also applies to: 77-100

bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/IDFTargetsReader.java (1)

49-56: Consider elevating missing constants.py to warning/error in logs

Currently logged as info; raising visibility can help users diagnose misconfiguration faster.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6f62d42 and ffa3fad.

📒 Files selected for processing (6)
  • bundles/com.espressif.idf.core/plugin.xml (0 hunks)
  • bundles/com.espressif.idf.core/src/com/espressif/idf/core/DefaultBoardProvider.java (1 hunks)
  • bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/ESPToolChainManager.java (1 hunks)
  • bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/IDFTargets.java (1 hunks)
  • bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/IDFTargetsReader.java (1 hunks)
  • bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/ToolsActivationJob.java (2 hunks)
💤 Files with no reviewable changes (1)
  • bundles/com.espressif.idf.core/plugin.xml
🧰 Additional context used
🧬 Code graph analysis (3)
bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/IDFTargetsReader.java (1)
bundles/com.espressif.idf.core/src/com/espressif/idf/core/logging/Logger.java (1)
  • Logger (21-137)
bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/ToolsActivationJob.java (2)
bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/IDFTargetsReader.java (1)
  • IDFTargetsReader (25-121)
bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/IDFUtil.java (1)
  • IDFUtil (59-996)
bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/ESPToolChainManager.java (3)
bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/IDFUtil.java (1)
  • IDFUtil (59-996)
bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/IDFTargetsReader.java (1)
  • IDFTargetsReader (25-121)
bundles/com.espressif.idf.core/src/com/espressif/idf/core/logging/Logger.java (1)
  • Logger (21-137)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build_windows
  • GitHub Check: build
🔇 Additional comments (4)
bundles/com.espressif.idf.core/src/com/espressif/idf/core/DefaultBoardProvider.java (1)

61-66: Good guard — downstream callers handle empty-string default

Verified call sites (JtagVariableResolver, ESPToolChainManager x2, NewSerialFlashTargetWizardPage): they safely accept an empty-string default (no NPE/AIOOBE); no changes required.

bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/IDFTargets.java (1)

177-188: Compiler pattern handling for unified layout looks good

Covers both target-specific and unified directory names and anchors on gcc executable. No issues.

Please verify on:

  • ESP-IDF v5.0.x (pre-unified Xtensa)
  • ESP-IDF v5.5+ (unified)
    that gcc paths match the pattern for esp32, esp32s2, esp32s3 and riscv targets.
bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/ToolsActivationJob.java (1)

29-29: Import looks correct

Using IDFTargetsReader directly here aligns with the dynamic discovery flow.

bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/ESPToolChainManager.java (1)

135-145: Init path logging is fine; ensure stale entries don’t mask missing toolchains

With the cache clear above, initToolChain will only add real, discoverable toolchains.

Copy link
Collaborator

@sigmaaa sigmaaa left a comment

Choose a reason for hiding this comment

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

LGTM. Added a few nits: we could simplify the switch cases or use a Set for the xtensa targets. Additionally, it would be good to add unit tests for IDFTargetsReader.java to improve test coverage.

Comment on lines 131 to 147
public String getArchitecture()
{
switch (name)
{
case "esp32": //$NON-NLS-1$
case "esp32s2": //$NON-NLS-1$
case "esp32s3": //$NON-NLS-1$
return "xtensa"; //$NON-NLS-1$
case "esp32c2": //$NON-NLS-1$
case "esp32c3": //$NON-NLS-1$
case "esp32c6": //$NON-NLS-1$
case "esp32h2": //$NON-NLS-1$
case "esp32p4": //$NON-NLS-1$
default:
return "riscv32"; //$NON-NLS-1$
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

NIT:
We could simplify the getArchitecture() method to make it more readable and avoid multiple riscv32 statements or returns. For example, using Java 21 switch expressions:

public String getArchitecture() {
    return switch (name) {
        case "esp32", "esp32s2", "esp32s3" -> "xtensa";
        default -> "riscv32";
    };
}

Alternatively, a Set-based approach could be used

private static final Set<String> XTENSA_CHIPS = Set.of("esp32", "esp32s2", "esp32s3");

public String getArchitecture() {
    return XTENSA_CHIPS.contains(name) ? "xtensa" : "riscv32";
}

Comment on lines 154 to 170
public String getToolchainId()
{
switch (name)
{
case "esp32": //$NON-NLS-1$
case "esp32s2": //$NON-NLS-1$
case "esp32s3": //$NON-NLS-1$
return "xtensa-" + name + "-elf"; //$NON-NLS-1$ //$NON-NLS-2$
case "esp32c2": //$NON-NLS-1$
case "esp32c3": //$NON-NLS-1$
case "esp32c6": //$NON-NLS-1$
case "esp32h2": //$NON-NLS-1$
case "esp32p4": //$NON-NLS-1$
default:
return "riscv32-esp-elf"; //$NON-NLS-1$
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

NIT: same as my earlier comment on getArchitecture() — we could simplify this in the same way using a switch expression or Set-based lookup.

@sigmaaa
Copy link
Collaborator

sigmaaa commented Sep 22, 2025

@AndriiFilippov PTAL

@AndriiFilippov
Copy link
Collaborator

AndriiFilippov commented Sep 23, 2025

@kolipakakondal @sigmaaa hi !

Tested under:
OS: Windows 11 / Linux Ubuntu 24.04
ESP-IDF: v5.5
Board: ESP32C5

LGTM in general.
do see toolchains added for preview targets under:
Preferences -> Core Build Toolchains
Preferences -> C/C++ -> CMake
able to build / flash / monitor / debug ✅

just small optimization:

  1. during project creation the list of available targets is missing preview targets
image

should we keep it like this or not ?

  1. there is kind of spam of info messages in logs, when selecting a target in Launch Target Editor:
image

I took some motivation from Denys's comments and further tried to enhance and generalize the class for future proofing. It adds a bit more code but the maintainability is not impacted and is much easier then trying to adjust or add targets in one class but multiple places
@alirana01
Copy link
Collaborator

@kolipakakondal @sigmaaa can you please review the PR again I have adjusted some of the comments but in a different way

I took some motivation from Denys's comments and further tried to enhance and generalize the class for future proofing. It adds a bit more code but the maintainability is not impacted and is much easier then trying to adjust or add targets in one class but multiple places

@alirana01 alirana01 requested a review from sigmaaa September 25, 2025 09:08
Copy link

@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: 6

🧹 Nitpick comments (1)
bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/enums/Architecture.java (1)

39-53: XTENSA unified vs target-specific executable prefixes: provide a pattern helper

For unified toolchains, Xtensa executables may be prefixed xtensa-esp-elf, whereas executablePrefixFor() returns only target-specific (e.g., xtensa-esp32s3-elf). Consider adding a helper that returns a regex alternation including both, and let Target use it for matching compiler/GDB.

Apply this addition (to be used by Target.compilerPattern()/debuggerPattern()):

 public String executablePrefixFor(Target t)
 {
   return toolchainPrefixFor(t);
 }
 
+/** Regex alternation to match both target-specific and unified prefixes when applicable. */
+public String executablePrefixPatternFor(Target t)
+{
+  String perTarget = toolchainPrefixFor(t);
+  if (this == XTENSA) {
+    return "(?:" + perTarget + "|xtensa-esp-elf)"; //$NON-NLS-1$
+  }
+  return perTarget;
+}
+
 public String targetSpecificDirFor(Target t)
 {
   return toolchainPrefixFor(t);
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ffa3fad and 014477a.

📒 Files selected for processing (3)
  • bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/IDFTargets.java (1 hunks)
  • bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/enums/Architecture.java (1 hunks)
  • bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/enums/Target.java (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build_macos
  • GitHub Check: build
  • GitHub Check: build_windows
🔇 Additional comments (1)
bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/IDFTargets.java (1)

74-87: Ignore preview‐targets suggestion
The project wizard (ToolsActivationJob) already calls getAllTargetNames(), so preview targets are included. No changes needed.

Likely an incorrect or invalid review comment.

Comment on lines 47 to 58
public static Target fromString(String s)
{
if (s == null)
return null;
String key = s.toLowerCase(Locale.ROOT);
for (Target t : values())
{
if (t.idfName.equals(key))
return t;
}
return null;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

fromString() hard-codes known targets — limits “future-proof” discovery

Returning null for unknown target names forces callers to drop them. Given the PR’s goal (new targets appear without plugin updates), relying solely on a fixed enum is brittle.

  • Either (A) expose a helper like Target.isXtensaName(String) (e.g., "esp32".equals(n) || n.startsWith("esp32s")) that downstream code can use as a fallback, or (B) replace enum with a dynamic model/class.
  • If keeping enum, ensure IDFTargets gracefully handles unknown names (see companion comment in IDFTargets.java).

Would you like me to draft a minimal helper API in this enum and wire it in IDFTargets to keep changes localized?


🏁 Script executed:

#!/bin/bash
# Locate IDFTargets.java declaration
rg -n --type java "class\s+IDFTargets" -C3

# Inspect usage of Target.fromString across Java code
rg -n --type java "Target\.fromString" -C3

Length of output: 4820


Handle unknown targets gracefully
In IDFTargets.java’s addSupportedTarget/addPreviewTarget, when Target.fromString(targetName) returns null, fall back to preserving the raw name—e.g.:

Target t = Target.fromString(targetName);
if (t != null) {
  supportedTargets.add(new IDFTarget(t, false));
} else {
  supportedTargets.add(new IDFTarget(targetName, false));
}

Alternatively, add to Target a helper like public static boolean isKnownName(String s) (e.g. Xtensa patterns) and use it for fallback. This prevents dropping new targets without plugin updates.

🤖 Prompt for AI Agents
In
bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/enums/Target.java
around lines 47 to 58, Target.fromString may return null for unknown/new targets
which causes callers to drop those names; update callers
(IDFTargets.addSupportedTarget/addPreviewTarget) to check the result of
Target.fromString and, if null, construct IDFTarget using the raw targetName
string (preserve the original name) OR add a Target helper like public static
boolean isKnownName(String s) and use it to decide whether to convert to a
Target or fall back to the raw name; ensure unknown names are not discarded so
new targets are preserved without plugin updates.

Comment on lines 97 to 104
/** Matches both legacy and unified layouts, ending with -gcc(.exe) */
public String compilerPattern()
{
String exe = executablePrefix();
String legacy = targetSpecificDirName();
String unified = unifiedDirName();
return "(?:" + legacy + "|" + unified + ")[\\\\/]+bin[\\\\/]+" + exe + "-gcc(?:\\.exe)?$"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Compiler detection breaks for unified Xtensa toolchains

The pattern uses only the target-specific prefix for executables (e.g., xtensa-esp32s3-elf-gcc), but unified toolchains may use xtensa-esp-elf-gcc. This will fail to detect compilers on unified Xtensa.

Apply this diff to accept both prefixes for Xtensa executables:

   public String compilerPattern()
   {
-    String exe = executablePrefix();
-    String legacy = targetSpecificDirName();
-    String unified = unifiedDirName();
-    return "(?:" + legacy + "|" + unified + ")[\\\\/]+bin[\\\\/]+" + exe + "-gcc(?:\\.exe)?$"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+    String legacy = targetSpecificDirName();
+    String unified = unifiedDirName();
+    // Accept both target-specific and unified prefixes for Xtensa executables
+    String exePattern = (arch() == Architecture.XTENSA)
+        ? "(?:" + executablePrefix() + "|xtensa-esp-elf)" //$NON-NLS-1$
+        : executablePrefix();
+    return "(?:" + legacy + "|" + unified + ")[\\\\/]+bin[\\\\/]+" + exePattern + "-gcc(?:\\.exe)?$"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
   }
📝 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
/** Matches both legacy and unified layouts, ending with -gcc(.exe) */
public String compilerPattern()
{
String exe = executablePrefix();
String legacy = targetSpecificDirName();
String unified = unifiedDirName();
return "(?:" + legacy + "|" + unified + ")[\\\\/]+bin[\\\\/]+" + exe + "-gcc(?:\\.exe)?$"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
/** Matches both legacy and unified layouts, ending with -gcc(.exe) */
public String compilerPattern()
{
String legacy = targetSpecificDirName();
String unified = unifiedDirName();
// Accept both target-specific and unified prefixes for Xtensa executables
String exePattern = (arch() == Architecture.XTENSA)
? "(?:" + executablePrefix() + "|xtensa-esp-elf)" //$NON-NLS-1$
: executablePrefix();
return "(?:" + legacy + "|" + unified + ")[\\\\/]+bin[\\\\/]+" + exePattern + "-gcc(?:\\.exe)?$"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
🤖 Prompt for AI Agents
In
bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/enums/Target.java
around lines 97 to 104, the compilerPattern() uses only executablePrefix(),
which misses unified Xtensa executables (e.g., xtensa-esp-elf-gcc). Update the
method to allow both prefixes for Xtensa by building a regex that alternates
executablePrefix() and the unified Xtensa prefix (e.g., "xtensa-esp-elf") when
this target is an Xtensa variant; construct exeAlternatives = executablePrefix()
or the alternate prefix for Xtensa and use that in the returned pattern as
(?:exeAlternatives)-gcc(?:\.exe)?$, so both legacy and unified Xtensa compiler
names are matched.

Comment on lines 106 to 109
public String debuggerPattern()
{
return executablePrefix() + "-gdb(?:\\.exe)?$"; //$NON-NLS-1$
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Debugger detection misses unified Xtensa GDB prefix

Same issue as compiler: only target-specific prefix is matched. Unified Xtensa ships xtensa-esp-elf-gdb.

Apply this diff:

   public String debuggerPattern()
   {
-    return executablePrefix() + "-gdb(?:\\.exe)?$"; //$NON-NLS-1$
+    if (arch() == Architecture.XTENSA) {
+      return "(?:" + executablePrefix() + "|xtensa-esp-elf)-gdb(?:\\.exe)?$"; //$NON-NLS-1$
+    }
+    return executablePrefix() + "-gdb(?:\\.exe)?$"; //$NON-NLS-1$
   }
📝 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
public String debuggerPattern()
{
return executablePrefix() + "-gdb(?:\\.exe)?$"; //$NON-NLS-1$
}
public String debuggerPattern()
{
if (arch() == Architecture.XTENSA) {
return "(?:" + executablePrefix() + "|xtensa-esp-elf)-gdb(?:\\.exe)?$"; //$NON-NLS-1$
}
return executablePrefix() + "-gdb(?:\\.exe)?$"; //$NON-NLS-1$
}
🤖 Prompt for AI Agents
In
bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/enums/Target.java
around lines 106-109, the debuggerPattern() currently only matches the
target-specific prefix and misses the unified Xtensa prefix
(xtensa-esp-elf-gdb); update the returned regex so the prefix is either
executablePrefix() or the literal "xtensa-esp-elf" (use a non-capturing
alternation group), followed by "-gdb" and the existing optional "\.exe" suffix,
preserving escaping and comments.

Comment on lines 31 to 36
public void addSupportedTarget(String targetName)
{
Target t = Target.fromString(targetName);
if (t != null)
supportedTargets.add(new IDFTarget(t, false));
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Dropping unknown targets breaks “future-proof” discovery

Target.fromString(targetName) returns null for new targets (e.g., esp32c5), so they never get added. This contradicts the PR objective of zero plugin updates for new targets.

Apply this diff to fallback to a dynamic target for unknown names:

   public void addSupportedTarget(String targetName)
   {
     Target t = Target.fromString(targetName);
-    if (t != null)
-      supportedTargets.add(new IDFTarget(t, false));
+    if (t != null) {
+      supportedTargets.add(new IDFTarget(t, false));
+    } else {
+      supportedTargets.add(IDFTarget.dynamic(targetName, false));
+    }
   }
📝 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
public void addSupportedTarget(String targetName)
{
Target t = Target.fromString(targetName);
if (t != null)
supportedTargets.add(new IDFTarget(t, false));
}
public void addSupportedTarget(String targetName)
{
Target t = Target.fromString(targetName);
if (t != null) {
supportedTargets.add(new IDFTarget(t, false));
} else {
supportedTargets.add(IDFTarget.dynamic(targetName, false));
}
}
🤖 Prompt for AI Agents
In
bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/IDFTargets.java
around lines 31 to 36, Target.fromString(targetName) returns null for
unknown/new targets so they are skipped; change the logic to fall back to
creating a dynamic target when t is null by constructing an IDFTarget that uses
the raw targetName and marks it as dynamic/unknown (instead of skipping), e.g.
when t != null keep existing new IDFTarget(t, false) else create a dynamic
IDFTarget using the name and a true dynamic flag so new targets (like esp32c5)
are preserved for “future-proof” discovery.

Comment on lines 38 to 43
public void addPreviewTarget(String targetName)
{
Target t = Target.fromString(targetName);
if (t != null)
previewTargets.add(new IDFTarget(t, true));
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Same issue for preview targets

Preview targets not present in the enum are silently ignored.

   public void addPreviewTarget(String targetName)
   {
     Target t = Target.fromString(targetName);
-    if (t != null)
-      previewTargets.add(new IDFTarget(t, true));
+    if (t != null) {
+      previewTargets.add(new IDFTarget(t, true));
+    } else {
+      previewTargets.add(IDFTarget.dynamic(targetName, true));
+    }
   }
📝 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
public void addPreviewTarget(String targetName)
{
Target t = Target.fromString(targetName);
if (t != null)
previewTargets.add(new IDFTarget(t, true));
}
public void addPreviewTarget(String targetName)
{
Target t = Target.fromString(targetName);
if (t != null) {
previewTargets.add(new IDFTarget(t, true));
} else {
previewTargets.add(IDFTarget.dynamic(targetName, true));
}
}
🤖 Prompt for AI Agents
In
bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/IDFTargets.java
around lines 38 to 43, the method addPreviewTarget currently ignores unknown
target names because Target.fromString returning null is silently skipped;
change this to the same behavior as the non-preview addTarget path by validating
the result of Target.fromString and throwing an IllegalArgumentException (or
otherwise reporting an error) if the targetName is not found so unknown preview
targets are not silently ignored.

Copy link
Collaborator

@sigmaaa sigmaaa left a comment

Choose a reason for hiding this comment

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

The goal of this PR is to include targets from the preview list even if they aren’t explicitly defined in our target list, based on the assumption that all new targets use the RICSV architecture. Therefore, returning null when a target isn’t found in the enum isn’t the behavior we want.

if (s == null)
return null;
String key = s.toLowerCase(Locale.ROOT);
for (Target t : values())
Copy link
Collaborator

Choose a reason for hiding this comment

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

If a value isn’t present in the enum but comes from the IDF preview list, our current approach returns null and skips it. That doesn’t align with the PR’s goal

Copy link
Collaborator

Choose a reason for hiding this comment

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

@sigmaaa kindly take a look again the code is updated now

@alirana01 alirana01 requested a review from sigmaaa September 25, 2025 11:07
Copy link

@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: 3

🧹 Nitpick comments (2)
bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/targets/Architecture.java (1)

41-57: Consider centralizing binary prefix alternatives (per‑target vs unified) here

TargetSpec now needs to know both toolchainPrefixFor(t) and unifiedDirName() to build robust patterns. Exposing a small helper here would reduce duplication and future mistakes.

Example addition:

 public enum Architecture {
   ...
+  /**
+   * Returns binary prefix candidates for this architecture, covering both legacy per-target
+   * and unified names (where applicable).
+   */
+  public String[] executablePrefixCandidatesFor(TargetSpec t) {
+    String primary = executablePrefixFor(t);
+    String unified = unifiedDirName();
+    return primary.equals(unified) ? new String[] { primary } : new String[] { primary, unified };
+  }
 }

Then TargetSpec can join candidates for gcc/gdb patterns.

bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/targets/Target.java (1)

55-60: Trim input before lookup to be more forgiving

Helps tolerate user/config inputs with stray spaces.

Apply this diff:

   public static Target tryParse(String s)
   {
     if (s == null)
       return null;
-    return BY_NAME.get(s.toLowerCase(Locale.ROOT));
+    String key = s.trim().toLowerCase(Locale.ROOT);
+    return BY_NAME.get(key);
   }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 014477a and f3b7996.

📒 Files selected for processing (5)
  • bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/IDFTargets.java (1 hunks)
  • bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/targets/Architecture.java (1 hunks)
  • bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/targets/Target.java (1 hunks)
  • bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/targets/TargetSpec.java (1 hunks)
  • bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/targets/internal/DynamicTarget.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/IDFTargets.java
🔇 Additional comments (3)
bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/targets/TargetSpec.java (1)

54-58: Confirm toolchain file naming remains per‑target under unified toolchains

Default toolchain-%s.cmake assumes per‑target files exist (e.g., toolchain-esp32s3.cmake). If ESP‑IDF ever ships a unified toolchain file (e.g., toolchain-esp-elf.cmake) for a subset of targets, this default will be wrong for dynamic/preview targets unless higher‑level code overrides it.

Please confirm that IDFTargetsReader always supplies the effective toolchain filename when deviating from the per‑target default and that callers prefer that source over this default. If not, we should allow TargetSpec implementations to override this or extend the API to source the filename from the dynamic data.

bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/targets/internal/DynamicTarget.java (1)

49-51: Java baseline check: pattern matching for instanceof requires Java 17+

if (!(o instanceof TargetSpec ts)) uses pattern variables. Ensure the project’s compiler level/baseline supports it. Otherwise, fall back to classic instanceof+cast.

If baseline < 17, replace with:

-    if (!(o instanceof TargetSpec ts))
-      return false;
-    return idfName.equals(ts.idfName());
+    if (!(o instanceof TargetSpec))
+      return false;
+    return idfName.equals(((TargetSpec) o).idfName());
bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/targets/Target.java (1)

28-30: Good: unmodifiable name lookup map for O(1) resolution

Creation via Collectors.toUnmodifiableMap avoids accidental mutation and duplicate keys.

Comment on lines 13 to 20
/**
* Represents a preview target that isn't (yet) in the {@link com.espressif.idf.core.target.Target} enum. Unknown
* preview targets default to RISCV32 unless specified otherwise.
*
* Keep this class in an internal package; consumers should rely on the TargetSpec API only.
*
* @author Ali Azam Rana
*/
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix Javadoc: wrong link and misleading default‑arch statement

  • Link references com.espressif.idf.core.target.Target; correct package is ...toolchain.targets.Target.
  • The “defaults to RISCV32” claim isn’t implemented here (ctor requires an Architecture). If that default happens elsewhere (e.g., IDFTargetsReader), clarify accordingly.

Apply this diff:

 /**
- * Represents a preview target that isn't (yet) in the {@link com.espressif.idf.core.target.Target} enum. Unknown
- * preview targets default to RISCV32 unless specified otherwise.
+ * Represents a preview target that isn't (yet) in the {@link com.espressif.idf.core.toolchain.targets.Target} enum.
+ * Selection of a default architecture (e.g., RISCV32) for unknown targets is handled by the dynamic reader;
+ * this class always carries an explicit {@link Architecture}.
  *
  * Keep this class in an internal package; consumers should rely on the TargetSpec API only.
📝 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
/**
* Represents a preview target that isn't (yet) in the {@link com.espressif.idf.core.target.Target} enum. Unknown
* preview targets default to RISCV32 unless specified otherwise.
*
* Keep this class in an internal package; consumers should rely on the TargetSpec API only.
*
* @author Ali Azam Rana
*/
/**
* Represents a preview target that isn't (yet) in the {@link com.espressif.idf.core.toolchain.targets.Target} enum.
* Selection of a default architecture (e.g., RISCV32) for unknown targets is handled by the dynamic reader;
* this class always carries an explicit {@link Architecture}.
*
* Keep this class in an internal package; consumers should rely on the TargetSpec API only.
*
* @author Ali Azam Rana
*/

Comment on lines 60 to 67
/** Matches legacy/unified dirs and ends with -gcc(.exe). */
default String compilerPattern()
{
String exe = executablePrefix();
String legacy = targetSpecificDirName();
String unified = unifiedDirName();
return "(?:" + legacy + "|" + unified + ")[\\\\/]+bin[\\\\/]+" + exe + "-gcc(?:\\.exe)?$"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Compiler regex likely misses unified Xtensa binary prefix; include both per‑target and unified prefixes

When Xtensa is unified, the binary prefix is typically xtensa-esp-elf, whereas executablePrefix() here resolves to per‑target (e.g., xtensa-esp32-elf). The current pattern would fail to match xtensa-esp-elf-gcc living under the unified dir. Make the binary portion accept both candidates.

Apply this diff:

  /** Matches legacy/unified dirs and ends with -gcc(.exe). */
  default String compilerPattern()
  {
-    String exe = executablePrefix();
-    String legacy = targetSpecificDirName();
-    String unified = unifiedDirName();
-    return "(?:" + legacy + "|" + unified + ")[\\\\/]+bin[\\\\/]+" + exe + "-gcc(?:\\.exe)?$"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+    String exePrimary = executablePrefix();
+    String exeUnified = arch().unifiedDirName();
+    String legacy = targetSpecificDirName();
+    String unified = unifiedDirName();
+    String exeAlt = "(?:" + exePrimary + "|" + exeUnified + ")";
+    return "(?:" + legacy + "|" + unified + ")[\\\\/]+bin[\\\\/]+" + exeAlt + "-gcc(?:\\.exe)?$"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
  }
🤖 Prompt for AI Agents
In
bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/targets/TargetSpec.java
around lines 60 to 67, the compilerPattern only uses executablePrefix() which
misses the unified Xtensa prefix (e.g., xtensa-esp-elf); compute a second
candidate by removing the final hyphenated target segment from
executablePrefix() (e.g., unifiedExe = exe.replaceFirst("-[^-]+$","")) and
update the regex to accept either the per-target exe or this unifiedExe when
matching the gcc binary (use a non-capturing alternation for the two prefixes in
the pattern).

Comment on lines 69 to 73
/** Matches <prefix>-gdb(.exe). */
default String debuggerPattern()
{
return executablePrefix() + "-gdb(?:\\.exe)?$"; //$NON-NLS-1$
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Debugger regex should also accept unified Xtensa binary prefix

Same concern as gcc pattern; match both per‑target and unified prefixes to avoid missing xtensa-esp-elf-gdb.

Apply this diff:

  /** Matches <prefix>-gdb(.exe). */
  default String debuggerPattern()
  {
-    return executablePrefix() + "-gdb(?:\\.exe)?$"; //$NON-NLS-1$
+    String exePrimary = executablePrefix();
+    String exeUnified = arch().unifiedDirName();
+    return "(?:" + exePrimary + "|" + exeUnified + ")-gdb(?:\\.exe)?$"; //$NON-NLS-1$
  }
📝 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
/** Matches <prefix>-gdb(.exe). */
default String debuggerPattern()
{
return executablePrefix() + "-gdb(?:\\.exe)?$"; //$NON-NLS-1$
}
/** Matches <prefix>-gdb(.exe). */
default String debuggerPattern()
{
String exePrimary = executablePrefix();
String exeUnified = arch().unifiedDirName();
return "(?:" + exePrimary + "|" + exeUnified + ")-gdb(?:\\.exe)?$"; //$NON-NLS-1$
}
🤖 Prompt for AI Agents
In
bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/targets/TargetSpec.java
around lines 69 to 73, the debuggerPattern() regex only accepts the per-target
executablePrefix and thus misses unified Xtensa prefixes like "xtensa-esp-elf";
update the pattern to accept either the per-target prefix or the unified prefix
by building an alternation between executablePrefix() and
unifiedExecutablePrefix() (e.g. use a non-capturing group
"(?:prefix|unifiedPrefix)" before "-gdb(?:\.exe)?$"), so the returned string
matches both forms.

Target known = Target.tryParse(targetName);
if (known == null)
{
throw new IllegalArgumentException("Unknown supported target: " + targetName); //$NON-NLS-1$
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don’t think this is the right approach. From my understanding, the goal of this PR is to avoid adding new targets directly in the code and instead rely fully on IDF, under the assumption that new targets will use the RISC-V architecture.

Copy link
Collaborator

@sigmaaa sigmaaa left a comment

Choose a reason for hiding this comment

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

LGTM! @AndriiFilippov please check

Copy link
Collaborator Author

@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.

Thanks @alirana01 for the changes, LGTM

Copy link

@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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between db964d1 and 51c14c6.

📒 Files selected for processing (1)
  • bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/templates/NewProjectCreationWizardPage.java (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/templates/NewProjectCreationWizardPage.java (1)
bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/IDFTargets.java (1)
  • IDFTargets (18-215)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build_windows
  • GitHub Check: build_macos
  • GitHub Check: build


import com.espressif.idf.core.configparser.EspConfigParser;
import com.espressif.idf.core.logging.Logger;
import com.espressif.idf.core.toolchain.IDFTargets;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Use IDFTargetsReader instead of a bare IDFTargets instance

Importing IDFTargets alone is insufficient here; a freshly constructed instance has no targets. Bring in IDFTargetsReader and populate from the current ESP‑IDF installation to actually enable dynamic discovery.

Apply this import adjustment:

 import com.espressif.idf.core.logging.Logger;
-import com.espressif.idf.core.toolchain.IDFTargets;
+import com.espressif.idf.core.toolchain.IDFTargets;
+import com.espressif.idf.core.toolchain.IDFTargetsReader;

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines 80 to 83
IDFTargets idfTargets = new IDFTargets();
targetCombo = new Combo(mainComposite, SWT.READ_ONLY);
targetCombo.setItems(parser.getTargets().toArray(new String[0]));
targetCombo.setItems(idfTargets.getAllTargets().stream().map(t -> t.getName()).toArray(String[]::new));
targetCombo.select(0);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Targets combo never populated (new IDFTargets() is empty) → preview targets missing and may show no items

Creating a new IDFTargets without reading from ESP‑IDF yields empty lists, so the combo remains empty and select(0) does nothing. This contradicts the PR goal and reviewer feedback about preview targets. Read targets via IDFTargetsReader, handle empty state, and prefer getAllTargetNames() (sorted) for consistency.

Proposed fix:

-        IDFTargets idfTargets = new IDFTargets();
         targetCombo = new Combo(mainComposite, SWT.READ_ONLY);
-        targetCombo.setItems(idfTargets.getAllTargets().stream().map(t -> t.getName()).toArray(String[]::new));
-        targetCombo.select(0);
+        String[] items = new String[0];
+        try {
+            // Resolve targets from the active ESP‑IDF installation
+            IDFTargets targets = new IDFTargetsReader().readTargetsFromEspIdf(IDFUtil.getIDFPath());
+            java.util.List<String> names = targets.getAllTargetNames();
+            names.sort(String::compareToIgnoreCase);
+            items = names.toArray(String[]::new);
+        } catch (Exception e) {
+            Logger.log(e);
+        }
+        targetCombo.setItems(items);
+        if (items.length > 0) {
+            targetCombo.select(0);
+            targetCombo.setEnabled(true);
+        } else {
+            targetCombo.setEnabled(false);
+            setMessage("No ESP‑IDF targets found. Check Preferences → ESP‑IDF and re-open the wizard.", IStatus.WARNING);
+        }
         targetCombo.setToolTipText(Messages.NewProjectTargetSelection_Tooltip);

Verification suggestions:

  • Confirm IDFUtil.getIDFPath() (or the correct resolver) exists; adjust the call if your utility uses a different method name.
  • If product intent is to include preview targets at project creation, getAllTargetNames() is correct. If not, switch to getSupportedTargetNames() or add a “Show preview targets” toggle.

🏁 Script executed:

#!/bin/bash
set -e

echo "Searching for IDFTargets class"
rg -nP --type=java 'class\s+IDFTargets\b'

echo "Searching for IDFTargets.getAllTargets method"
rg -nP --type=java 'getAllTargets\s*\(' -n

echo "Searching for IDFTargets.getAllTargetNames method"
rg -nP --type=java 'getAllTargetNames\s*\(' -n

echo "Searching for IDFTargetsReader class"
rg -nP --type=java 'class\s+IDFTargetsReader\b'

echo "Searching for IDFTargetsReader.readTargetsFromEspIdf"
rg -nP --type=java 'readTargetsFromEspIdf\s*\(' -n

echo "Searching for IDFUtil.getIDFPath"
rg -nP --type=java 'IDFUtil.getIDFPath' -n

Length of output: 5967


🏁 Script executed:

#!/bin/bash
set -e

echo "Show lines 1-60 of IDFTargets.java"
sed -n '1,60p' bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/IDFTargets.java

Length of output: 1928


Load and display ESP-IDF targets via the reader, not the empty default
The no-arg new IDFTargets() constructor initializes empty lists, so getAllTargets() yields no items. Replace it with IDFTargetsReader.readTargetsFromEspIdf(IDFUtil.getIDFPath()), sort the resulting getAllTargetNames(), populate the combo, and disable it with a warning if no targets are found.

-        IDFTargets idfTargets = new IDFTargets();
         targetCombo = new Combo(mainComposite, SWT.READ_ONLY);
-        targetCombo.setItems(idfTargets.getAllTargets().stream().map(t -> t.getName()).toArray(String[]::new));
-        targetCombo.select(0);
+        String[] items = new String[0];
+        try {
+            IDFTargets targets = IDFTargetsReader.readTargetsFromEspIdf(IDFUtil.getIDFPath());
+            List<String> names = targets.getAllTargetNames();
+            names.sort(String::compareToIgnoreCase);
+            items = names.toArray(String[]::new);
+        } catch (Exception e) {
+            Logger.log(e);
+        }
+        targetCombo.setItems(items);
+        if (items.length > 0) {
+            targetCombo.select(0);
+            targetCombo.setEnabled(true);
+        } else {
+            targetCombo.setEnabled(false);
+            setMessage("No ESP-IDF targets found. Check Preferences → ESP-IDF and re-open the wizard.", IStatus.WARNING);
+        }
         targetCombo.setToolTipText(Messages.NewProjectTargetSelection_Tooltip);
📝 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
IDFTargets idfTargets = new IDFTargets();
targetCombo = new Combo(mainComposite, SWT.READ_ONLY);
targetCombo.setItems(parser.getTargets().toArray(new String[0]));
targetCombo.setItems(idfTargets.getAllTargets().stream().map(t -> t.getName()).toArray(String[]::new));
targetCombo.select(0);
// Populate the targetCombo from ESP-IDF, sorted, with a warning if none are found
targetCombo = new Combo(mainComposite, SWT.READ_ONLY);
String[] items = new String[0];
try {
IDFTargets targets = IDFTargetsReader.readTargetsFromEspIdf(IDFUtil.getIDFPath());
List<String> names = targets.getAllTargetNames();
names.sort(String::compareToIgnoreCase);
items = names.toArray(String[]::new);
} catch (Exception e) {
Logger.log(e);
}
targetCombo.setItems(items);
if (items.length > 0) {
targetCombo.select(0);
targetCombo.setEnabled(true);
} else {
targetCombo.setEnabled(false);
setMessage(
"No ESP-IDF targets found. Check Preferences → ESP-IDF and re-open the wizard.",
IStatus.WARNING
);
}
targetCombo.setToolTipText(Messages.NewProjectTargetSelection_Tooltip);
🤖 Prompt for AI Agents
In
bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/templates/NewProjectCreationWizardPage.java
around lines 80 to 83, the code instantiates an empty IDFTargets via new
IDFTargets() which yields no targets; replace this with loading targets using
IDFTargetsReader.readTargetsFromEspIdf(IDFUtil.getIDFPath()), retrieve the list
of target names via getAllTargetNames(), sort them, call
targetCombo.setItems(...) with the sorted names, and if the resulting list is
empty disable the combo and set a visible warning label/message explaining no
targets were found.

@AndriiFilippov
Copy link
Collaborator

@alirana01 hi !

Tested under:
OS: Windows 11 / Linux Ubuntu 24.04 / Mac arm64
ESP-IDF: v5.5.1
Board: ESP32C5

do see toolchains added for preview targets under:
Preferences -> Core Build Toolchains ✅
Preferences -> C/C++ -> CMake ✅
able to build / flash / monitor / debug ✅
during project creation the list of available targets ✅
all targets are visible ✅

LGTM

@alirana01 alirana01 merged commit 1c92ec9 into master Oct 3, 2025
6 checks passed
@alirana01 alirana01 deleted the toolchain_refactor branch October 3, 2025 11:07
@kolipakakondal kolipakakondal added this to the v3.7.0 milestone Oct 9, 2025
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.

5 participants