diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/IDFCorePreferenceConstants.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/IDFCorePreferenceConstants.java index 2fde5d21c..d9d7c9e6a 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/IDFCorePreferenceConstants.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/IDFCorePreferenceConstants.java @@ -25,6 +25,7 @@ public class IDFCorePreferenceConstants public static final String AUTOMATE_BUILD_HINTS_STATUS = "automateHintsStatus"; //$NON-NLS-1$ public static final String HIDE_ERRORS_IDF_COMPONENTS = "hideErrorsOnIdfDerivedFiles"; //$NON-NLS-1$ public static final String AUTOMATE_CLANGD_FORMAT_FILE = "automateClangFormatFileCreation"; //$NON-NLS-1$ + public static final String EIM_IDF_JSON_PATH = "eimIdfJsonPath"; //$NON-NLS-1$ public static final boolean AUTOMATE_CLANGD_FORMAT_FILE_DEFAULT = true; public static final boolean CMAKE_CCACHE_DEFAULT_STATUS = true; public static final boolean AUTOMATE_BUILD_HINTS_DEFAULT_STATUS = true; diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimIdfConfiguratinParser.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimIdfConfiguratinParser.java index 05e38d7e1..ddbdcc240 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimIdfConfiguratinParser.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimIdfConfiguratinParser.java @@ -3,8 +3,7 @@ import java.io.File; import java.io.FileReader; import java.io.IOException; - -import org.eclipse.core.runtime.Platform; +import java.nio.file.Path; import com.espressif.idf.core.logging.Logger; import com.espressif.idf.core.tools.exceptions.EimVersionMismatchException; @@ -25,9 +24,8 @@ public EimIdfConfiguratinParser() private void load() throws IOException, EimVersionMismatchException { - String path = Platform.getOS().equals(Platform.OS_WIN32) ? EimConstants.EIM_WIN_PATH - : EimConstants.EIM_POSIX_PATH; - + Path jsonPath = new EimIdfJsonPathResolver().resolveEimIdfJsonFile(); + String path = jsonPath.toString(); File file = new File(path); if (!file.exists()) { diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimIdfJsonPathResolver.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimIdfJsonPathResolver.java new file mode 100644 index 000000000..ccb6f9f85 --- /dev/null +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimIdfJsonPathResolver.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright 2025 Espressif Systems (Shanghai) PTE LTD. All rights reserved. + * Use is subject to license terms. + *******************************************************************************/ +package com.espressif.idf.core.tools; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.preferences.InstanceScope; + +import com.espressif.idf.core.IDFCorePlugin; +import com.espressif.idf.core.IDFCorePreferenceConstants; + +/** + * @author Kondal Kolipaka + * + */ +public class EimIdfJsonPathResolver +{ + public Path resolveEimIdfJsonFile() + { + String custom = InstanceScope.INSTANCE.getNode(IDFCorePlugin.PLUGIN_ID) + .get(IDFCorePreferenceConstants.EIM_IDF_JSON_PATH, ""); //$NON-NLS-1$ + return resolveEimIdfJsonFileFromPreferenceString(custom); + } + + public Path resolveEimIdfJsonFileFromPreferenceString(String custom) + { + if (custom != null && !custom.isEmpty()) + { + Path p = Paths.get(custom); + if (p.getFileName() != null + && p.getFileName().toString().equals(EimConstants.EIM_JSON) + && Files.isRegularFile(p)) + { + return p; + } + } + return getDefaultEimIdfJsonFile(); + } + + public String getDefaultEimIdfJsonPathString() + { + return Platform.getOS().equals(Platform.OS_WIN32) ? EimConstants.EIM_WIN_PATH : EimConstants.EIM_POSIX_PATH; + } + + public Path getDefaultEimIdfJsonFile() + { + return Paths.get(getDefaultEimIdfJsonPathString()); + } +} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimLoader.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimLoader.java index 88ea9a67e..9c973cb44 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimLoader.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimLoader.java @@ -140,7 +140,11 @@ protected IStatus run(IProgressMonitor monitor) @Override public void aboutToRun(IJobChangeEvent event) { - EimJsonWatchService.getInstance().pauseListeners(); + EimJsonWatchService ws = EimJsonWatchService.getInstance(); + if (ws != null) + { + ws.pauseListeners(); + } } @Override @@ -162,7 +166,11 @@ public void done(IJobChangeEvent event) callback.run(); } - EimJsonWatchService.getInstance().unpauseListeners(); + EimJsonWatchService ws2 = EimJsonWatchService.getInstance(); + if (ws2 != null) + { + ws2.unpauseListeners(); + } } }); diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/ToolInitializer.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/ToolInitializer.java index b577bbc1c..13095d2c3 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/ToolInitializer.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/ToolInitializer.java @@ -62,9 +62,8 @@ public boolean isEimInstalled() public boolean isEimIdfJsonPresent() { - String path = Platform.getOS().equals(Platform.OS_WIN32) ? EimConstants.EIM_WIN_PATH - : EimConstants.EIM_POSIX_PATH; - return new File(path).exists(); + Path path = new EimIdfJsonPathResolver().resolveEimIdfJsonFile(); + return Files.isRegularFile(path) && Files.isReadable(path); } public EimJson loadEimJson() throws EimVersionMismatchException diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/watcher/EimJsonStateChecker.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/watcher/EimJsonStateChecker.java index 44232e9eb..23bafe2fb 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/watcher/EimJsonStateChecker.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/watcher/EimJsonStateChecker.java @@ -6,11 +6,10 @@ import java.io.File; -import org.eclipse.core.runtime.Platform; import org.osgi.service.prefs.Preferences; import com.espressif.idf.core.logging.Logger; -import com.espressif.idf.core.tools.EimConstants; +import com.espressif.idf.core.tools.EimIdfJsonPathResolver; /** * Checks if eim_idf.json was changed while Eclipse was not running. Stores and compares last seen timestamp to file @@ -62,6 +61,6 @@ public void updateLastSeenTimestamp() private String getEimJsonPath() { - return Platform.getOS().equals(Platform.OS_WIN32) ? EimConstants.EIM_WIN_PATH : EimConstants.EIM_POSIX_PATH; + return new EimIdfJsonPathResolver().resolveEimIdfJsonFile().toString(); } } diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/watcher/EimJsonWatchService.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/watcher/EimJsonWatchService.java index 8c417a230..7d092c3b6 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/watcher/EimJsonWatchService.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/watcher/EimJsonWatchService.java @@ -9,26 +9,26 @@ import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.nio.file.StandardWatchEventKinds; import java.nio.file.WatchEvent; import java.nio.file.WatchKey; import java.nio.file.WatchService; import java.time.Instant; import java.time.temporal.ChronoUnit; +import java.util.ArrayList; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; -import org.eclipse.core.runtime.Platform; - import com.espressif.idf.core.logging.Logger; import com.espressif.idf.core.tools.EimConstants; +import com.espressif.idf.core.tools.EimIdfJsonPathResolver; /** * eim_idf.json watch service. The service will only watch for changes. Any handling must be done by the listeners to * this service. * * @author Ali Azam Rana + * */ public class EimJsonWatchService extends Thread { @@ -41,29 +41,40 @@ public class EimJsonWatchService extends Thread private EimJsonWatchService() throws IOException { - String directoryPathString = Platform.getOS().equals(Platform.OS_WIN32) ? EimConstants.EIM_WIN_DIR - : EimConstants.EIM_POSIX_DIR; - - watchDirectoryPath = Paths.get(directoryPathString); + EimIdfJsonPathResolver r = new EimIdfJsonPathResolver(); + Path json = r.resolveEimIdfJsonFile(); + Path def = r.getDefaultEimIdfJsonFile(); + if (json.getParent() == null) + { + throw new IOException("Invalid eim_idf.json path"); //$NON-NLS-1$ + } + watchDirectoryPath = json.getParent(); + if (json.toAbsolutePath().normalize().equals(def.toAbsolutePath().normalize())) + { + if (!Files.exists(watchDirectoryPath)) + { + Files.createDirectories(watchDirectoryPath); + } + } if (!Files.exists(watchDirectoryPath)) { - Files.createDirectories(watchDirectoryPath); + throw new IOException("Directory for eim_idf.json does not exist: " + watchDirectoryPath); //$NON-NLS-1$ } watchService = FileSystems.getDefault().newWatchService(); watchDirectoryPath.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY); - Logger.log("Watcher added to the directory: " + directoryPathString); //$NON-NLS-1$ + Logger.log("Watcher added to the directory: " + watchDirectoryPath); //$NON-NLS-1$ setName("EimJsonWatchService"); //$NON-NLS-1$ setDaemon(true); start(); } - private static class Holder - { - private static EimJsonWatchService INSTANCE; + private static EimJsonWatchService INSTANCE; - static + public static synchronized EimJsonWatchService getInstance() + { + if (INSTANCE == null) { try { @@ -75,11 +86,52 @@ private static class Holder Logger.log(e); } } + return INSTANCE; + } + + public static synchronized void restartAfterEimIdfPathChange() + { + EimJsonWatchService old = INSTANCE; + List toCopy = (old == null) ? new ArrayList<>() : new ArrayList<>(old.eimJsonChangeListeners); + try + { + EimJsonWatchService fresh = new EimJsonWatchService(); + for (EimJsonChangeListener l : toCopy) + { + fresh.addEimJsonChangeListener(l); + } + INSTANCE = fresh; + if (old != null) + { + old.requestStop(); + } + } + catch (IOException e) + { + Logger.log("Failed to restart EimJsonWatchService"); //$NON-NLS-1$ + Logger.log(e); + } } - public static EimJsonWatchService getInstance() + private void requestStop() { - return Holder.INSTANCE; + running = false; + try + { + watchService.close(); + } + catch (IOException e) + { + Logger.log(e); + } + try + { + join(10_000); + } + catch (InterruptedException e) + { + Thread.currentThread().interrupt(); + } } public void addEimJsonChangeListener(EimJsonChangeListener listener) @@ -97,9 +149,21 @@ public void removeAllListeners() public static void withPausedListeners(Runnable task) { - EimJsonWatchService watchService = getInstance(); - boolean wasPaused = watchService.paused; - watchService.pauseListeners(); + EimJsonWatchService watch = getInstance(); + if (watch == null) + { + try + { + task.run(); + } + catch (Exception e) + { + Logger.log(e); + } + return; + } + boolean wasPaused = watch.paused; + watch.pauseListeners(); try { @@ -111,7 +175,7 @@ public static void withPausedListeners(Runnable task) } finally { if (!wasPaused) - watchService.unpauseListeners(); + watch.unpauseListeners(); } } diff --git a/bundles/com.espressif.idf.terminal.connector/src/com/espressif/idf/terminal/connector/launcher/IDFTerminalProcessConnector.java b/bundles/com.espressif.idf.terminal.connector/src/com/espressif/idf/terminal/connector/launcher/IDFTerminalProcessConnector.java index 98a77cbfa..cc90563fe 100644 --- a/bundles/com.espressif.idf.terminal.connector/src/com/espressif/idf/terminal/connector/launcher/IDFTerminalProcessConnector.java +++ b/bundles/com.espressif.idf.terminal.connector/src/com/espressif/idf/terminal/connector/launcher/IDFTerminalProcessConnector.java @@ -9,17 +9,15 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Objects; import java.util.Optional; import java.util.stream.StreamSupport; -import org.eclipse.core.runtime.Platform; import org.eclipse.terminal.connector.ITerminalControl; import org.eclipse.terminal.connector.process.ProcessConnector; import com.espressif.idf.core.IDFEnvironmentVariables; import com.espressif.idf.core.logging.Logger; -import com.espressif.idf.core.tools.EimConstants; +import com.espressif.idf.core.tools.EimIdfJsonPathResolver; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; import com.google.gson.JsonParser; @@ -59,14 +57,7 @@ private void sendCommand(OutputStream out, String command) { } private Optional getActivationScriptPath() { - var envPath = Objects.equals(Platform.getOS(), Platform.OS_WIN32) ? EimConstants.EIM_WIN_PATH - : EimConstants.EIM_POSIX_PATH; - - if (envPath == null) { - return Optional.empty(); - } - - var path = Path.of(envPath); + var path = new EimIdfJsonPathResolver().resolveEimIdfJsonFile(); if (!Files.exists(path)) { return Optional.empty(); } diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/preferences/EspresssifPreferencesPage.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/preferences/EspresssifPreferencesPage.java index 672424e22..dbc288cac 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/preferences/EspresssifPreferencesPage.java +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/preferences/EspresssifPreferencesPage.java @@ -1,14 +1,21 @@ package com.espressif.idf.ui.preferences; +import java.nio.file.Paths; +import java.util.Objects; + import org.eclipse.core.runtime.preferences.InstanceScope; +import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.preference.PreferencePage; import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; @@ -19,6 +26,8 @@ import com.espressif.idf.core.IDFCorePlugin; import com.espressif.idf.core.IDFCorePreferenceConstants; import com.espressif.idf.core.logging.Logger; +import com.espressif.idf.core.tools.EimConstants; +import com.espressif.idf.core.tools.watcher.EimJsonWatchService; public class EspresssifPreferencesPage extends PreferencePage implements IWorkbenchPreferencePage { @@ -39,6 +48,7 @@ public class EspresssifPreferencesPage extends PreferencePage implements IWorkbe private Combo gitAssetsCombo; private Combo pythonWheelCombo; private Button automateClangdFormatCreationBtn; + private Text eimIdfJsonPathText; public EspresssifPreferencesPage() { @@ -76,9 +86,53 @@ protected Control createContents(Composite parent) addBuildSettings(mainComposite); addClangdSettings(mainComposite); + + addEimSettings(mainComposite); return mainComposite; } + private void addEimSettings(Composite mainComposite) + { + Group eimGroup = new Group(mainComposite, SWT.SHADOW_ETCHED_IN); + eimGroup.setText(Messages.EspresssifPreferencesPage_EimSettingsGroupName); + eimGroup.setLayout(new GridLayout(3, false)); + + Label eimPathLabel = new Label(eimGroup, SWT.None); + eimPathLabel.setText(Messages.EspresssifPreferencesPage_EimIdfJsonPathLabel); + eimIdfJsonPathText = new Text(eimGroup, SWT.SINGLE | SWT.BORDER); + GridData eimPathTextData = new GridData(SWT.FILL, SWT.CENTER, true, false); + eimPathTextData.widthHint = 500; + eimIdfJsonPathText.setLayoutData(eimPathTextData); + eimIdfJsonPathText.setText(getPreferenceStore().getString(IDFCorePreferenceConstants.EIM_IDF_JSON_PATH)); + eimIdfJsonPathText.setToolTipText(Messages.EspresssifPreferencesPage_EimIdfJsonPathTooltip); + eimIdfJsonPathText.setMessage("Leave empty to use the default value."); //$NON-NLS-1$ + Button eimPathBrowse = new Button(eimGroup, SWT.PUSH); + eimPathBrowse.setText(Messages.EspresssifPreferencesPage_EimIdfJsonPathBrowse); + eimPathBrowse.addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetSelected(SelectionEvent e) + { + FileDialog d = new FileDialog(eimIdfJsonPathText.getShell(), SWT.OPEN); + d.setFileName(EimConstants.EIM_JSON); + String s = d.open(); + if (s != null) + { + if (!Paths.get(s).getFileName().toString().equals(EimConstants.EIM_JSON)) + { + MessageDialog.openError(eimPathBrowse.getShell(), + Messages.EspresssifPreferencesPage_EimSettingsGroupName, + Messages.EspresssifPreferencesPage_EimIdfJsonPathInvalid); + } + else + { + eimIdfJsonPathText.setText(s); + } + } + } + }); + } + private void addClangdSettings(Composite mainComposite) { Group clangdOptionsGroup = new Group(mainComposite, SWT.SHADOW_ETCHED_IN); @@ -195,6 +249,21 @@ public boolean performOk() getPreferenceStore().setValue(IDFCorePreferenceConstants.AUTOMATE_CLANGD_FORMAT_FILE, automateClangdFormatCreationBtn.getSelection()); + + String eimIdf = eimIdfJsonPathText.getText().trim(); + if (!eimIdf.isEmpty() + && !Paths.get(eimIdf).getFileName().toString().equals(EimConstants.EIM_JSON)) + { + MessageDialog.openError(getShell(), Messages.EspresssifPreferencesPage_EimSettingsGroupName, + Messages.EspresssifPreferencesPage_EimIdfJsonPathInvalid); + return false; + } + String prevEim = getPreferenceStore().getString(IDFCorePreferenceConstants.EIM_IDF_JSON_PATH); + getPreferenceStore().setValue(IDFCorePreferenceConstants.EIM_IDF_JSON_PATH, eimIdf); + if (!Objects.equals(prevEim, eimIdf)) + { + EimJsonWatchService.restartAfterEimIdfPathChange(); + } } catch (Exception e) { @@ -218,6 +287,8 @@ protected void performDefaults() .setSelection(getPreferenceStore().getBoolean(IDFCorePreferenceConstants.HIDE_ERRORS_IDF_COMPONENTS)); automateClangdFormatCreationBtn .setSelection(getPreferenceStore().getBoolean(IDFCorePreferenceConstants.AUTOMATE_CLANGD_FORMAT_FILE)); + eimIdfJsonPathText + .setText(getPreferenceStore().getDefaultString(IDFCorePreferenceConstants.EIM_IDF_JSON_PATH)); gitAssetsCombo.setText(gitAssetsCombo.getItem(0)); pythonWheelCombo.setText(pythonWheelCombo.getItem(0)); } @@ -235,5 +306,6 @@ private void initializeDefaults() IDFCorePreferenceConstants.HIDE_ERRORS_IDF_COMPONENTS_DEFAULT_STATUS); getPreferenceStore().setDefault(IDFCorePreferenceConstants.AUTOMATE_CLANGD_FORMAT_FILE, IDFCorePreferenceConstants.AUTOMATE_CLANGD_FORMAT_FILE_DEFAULT); + getPreferenceStore().setDefault(IDFCorePreferenceConstants.EIM_IDF_JSON_PATH, ""); //$NON-NLS-1$ } } diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/preferences/Messages.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/preferences/Messages.java index 4ad529b1b..da73a4fc9 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/preferences/Messages.java +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/preferences/Messages.java @@ -10,6 +10,11 @@ public class Messages extends NLS public static String EspresssifPreferencesPage_BuildGroupTxt; public static String EspresssifPreferencesPage_CCacheToolTip; public static String EspresssifPreferencesPage_ClangdSettingsGroupName; + public static String EspresssifPreferencesPage_EimSettingsGroupName; + public static String EspresssifPreferencesPage_EimIdfJsonPathLabel; + public static String EspresssifPreferencesPage_EimIdfJsonPathTooltip; + public static String EspresssifPreferencesPage_EimIdfJsonPathBrowse; + public static String EspresssifPreferencesPage_EimIdfJsonPathInvalid; public static String EspresssifPreferencesPage_EnableCCache; public static String EspresssifPreferencesPage_IDFSpecificPrefs; public static String EspresssifPreferencesPage_SearchHintsCheckBtn; diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/preferences/messages.properties b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/preferences/messages.properties index 546203925..93b735625 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/preferences/messages.properties +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/preferences/messages.properties @@ -3,6 +3,11 @@ EspresssifPreferencesPage_AutoCreateClangFormatTooltipMsg=Ensures .clang-format EspresssifPreferencesPage_BuildGroupTxt=Build Settings EspresssifPreferencesPage_CCacheToolTip=This sets CCACHE_ENABLE=1 to the IDF CMake build, if the CCache tool is installed EspresssifPreferencesPage_ClangdSettingsGroupName=Clangd Settings +EspresssifPreferencesPage_EimSettingsGroupName=ESP-IDF Installation Manager Settings +EspresssifPreferencesPage_EimIdfJsonPathLabel=Path for eim_idf.json file +EspresssifPreferencesPage_EimIdfJsonPathTooltip=If empty, the default location is used. If a custom file does not exist, the default is used. The file name must be eim_idf.json. +EspresssifPreferencesPage_EimIdfJsonPathBrowse=Browse\u2026 +EspresssifPreferencesPage_EimIdfJsonPathInvalid=The file name must be eim_idf.json EspresssifPreferencesPage_EnableCCache=Enable Ccache EspresssifPreferencesPage_IDFSpecificPrefs=ESP-IDF Specific Preferences. EspresssifPreferencesPage_SearchHintsCheckBtn=Search hints for build errors (may affect build performance) diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/preferences/messages_zh.properties b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/preferences/messages_zh.properties index efdc2a1e6..3238d4195 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/preferences/messages_zh.properties +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/preferences/messages_zh.properties @@ -7,3 +7,9 @@ SerialMonitorPage_Field_NumberOfLines=\u9650\u5236\u63a7\u5236\u53f0\u8f93\u51fa EspresssifPreferencesPage_CCacheToolTip=\u8fd9\u5c06\u8bbe\u7f6e CCACHE_ENABLE EspresssifPreferencesPage_EnableCCache=\u542f\u7528 CMake CCache +EspresssifPreferencesPage_EimSettingsGroupName=ESP-IDF \u5b89\u88c5\u7ba1\u7406\u5668\u8bbe\u7f6e +EspresssifPreferencesPage_EimIdfJsonPathLabel=eim_idf.json \u6587\u4ef6\u8def\u5f84 +EspresssifPreferencesPage_EimIdfJsonPathTooltip=\u7559\u7a7a\u5219\u4f7f\u7528\u9ed8\u8ba4\u4f4d\u7f6e\u3002\u81ea\u5b9a\u4e49\u6587\u4ef6\u4e0d\u5b58\u5728\u65f6\u4f1a\u56de\u9000\u5230\u9ed8\u8ba4\u4f4d\u7f6e\u3002\u6587\u4ef6\u540d\u5fc5\u987b\u4e3a eim_idf.json\u3002 +EspresssifPreferencesPage_EimIdfJsonPathBrowse=\u6d4f\u89c8\u2026 +EspresssifPreferencesPage_EimIdfJsonPathInvalid=\u6587\u4ef6\u540d\u5fc5\u987b\u4e3a eim_idf.json + diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/EspressifToolStartup.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/EspressifToolStartup.java index 9874bb8d9..a2b4ffd4a 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/EspressifToolStartup.java +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/EspressifToolStartup.java @@ -79,7 +79,11 @@ public void earlyStartup() eimLoader = new EimLoader(new StartupClassDownloadEimDownloadListener(), standardConsoleStream, errorConsoleStream, Display.getDefault()); eimJsonUiChangeHandler = new EimJsonUiChangeHandler(preferences); - EimJsonWatchService.getInstance().addEimJsonChangeListener(eimJsonUiChangeHandler); + EimJsonWatchService w = EimJsonWatchService.getInstance(); + if (w != null) + { + w.addEimJsonChangeListener(eimJsonUiChangeHandler); + } if (!toolInitializer.isEimInstalled() && !toolInitializer.isEimIdfJsonPresent()) { diff --git a/docs/en/installation.rst b/docs/en/installation.rst index c20ab1e6f..a91415c82 100644 --- a/docs/en/installation.rst +++ b/docs/en/installation.rst @@ -73,6 +73,15 @@ The refresh button in the last column for the active ESP-IDF version can be used .. image:: ../../media/ToolsManager/ESP-IDF_Manager_Changed_Installation_Message.png +.. _eim-idf-json-path: + +``eim_idf.json`` path +~~~~~~~~~~~~~~~~~~~~~ + +EIM stores your ESP-IDF installs in a file named ``eim_idf.json``. By default it is here: **Windows** — ``C:\\Espressif\\tools\\eim_idf.json``; **Linux / macOS** — ``~/.espressif/tools/eim_idf.json``. + +If you installed ESP-IDF or tools to a **custom location**, EIM may write ``eim_idf.json`` under that layout instead. The IDE only checks the default path above, so it will **not** see your setup until you point it at the real file: **Window** > **Preferences** > **Espressif** > **ESP-IDF Installation Manager settings** — use **Browse** (or type the path) for **Path for eim_idf.json file**; the file name must be ``eim_idf.json``. Leave empty to use the default only. More detail: `EIM documentation `__. + .. _esp-idf-tools-migration: Old-to-New Workspace Migration diff --git a/docs/zh_CN/installation.rst b/docs/zh_CN/installation.rst index e8e501391..395340abb 100644 --- a/docs/zh_CN/installation.rst +++ b/docs/zh_CN/installation.rst @@ -73,6 +73,15 @@ Espressif-IDE 提供了工具管理视图,可用来激活可用的 ESP-IDF 版 .. image:: ../../media/ToolsManager/ESP-IDF_Manager_Changed_Installation_Message.png +.. _eim-idf-json-path: + +``eim_idf.json`` 路径 +~~~~~~~~~~~~~~~~~~~~~ + +EIM 用 ``eim_idf.json`` 保存你的 ESP-IDF 安装信息。默认路径为:**Windows** — ``C:\\Espressif\\tools\\eim_idf.json``;**Linux / macOS** — ``~/.espressif/tools/eim_idf.json``。 + +若将 ESP-IDF 或工具装到\ **自定义目录**\ ,EIM 可能把 ``eim_idf.json`` 写在该目录结构下。IDE 默认只查找上述位置,\ **无法自动发现**\ 时,请打开 **窗口** > **首选项** > **Espressif** > **ESP-IDF 安装管理器设置**\ ,用 **浏览**\ (或手填)指定 **eim_idf.json 文件路径**\ (文件名须为 ``eim_idf.json``)。留空则仅用默认路径。更多说明见 `EIM 文档 `__。 + .. _esp-idf-tools-migration: 迁移旧工作区到新工作区 diff --git a/tests/com.espressif.idf.core.test/src/com/espressif/idf/core/tools/test/EimIdfJsonPathResolverTest.java b/tests/com.espressif.idf.core.test/src/com/espressif/idf/core/tools/test/EimIdfJsonPathResolverTest.java new file mode 100644 index 000000000..fb0c2a243 --- /dev/null +++ b/tests/com.espressif.idf.core.test/src/com/espressif/idf/core/tools/test/EimIdfJsonPathResolverTest.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright 2025 Espressif Systems (Shanghai) PTE LTD. All rights reserved. + * Use is subject to license terms. + *******************************************************************************/ +package com.espressif.idf.core.tools.test; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import com.espressif.idf.core.tools.EimIdfJsonPathResolver; + +/** + * @author Kondal Kolipaka + * + */ +public class EimIdfJsonPathResolverTest +{ + + @Test + void empty_preference_uses_default_path() + { + EimIdfJsonPathResolver r = new EimIdfJsonPathResolver(); + Path result = r.resolveEimIdfJsonFileFromPreferenceString(""); + Assertions.assertEquals(r.getDefaultEimIdfJsonFile(), result); + } + + @Test + void null_preference_uses_default_path() + { + EimIdfJsonPathResolver r = new EimIdfJsonPathResolver(); + Path result = r.resolveEimIdfJsonFileFromPreferenceString(null); + Assertions.assertEquals(r.getDefaultEimIdfJsonFile(), result); + } + + @Test + void existing_custom_file_is_used(@TempDir Path tempDir) throws IOException + { + Path json = tempDir.resolve("eim_idf.json"); + Files.createFile(json); + EimIdfJsonPathResolver r = new EimIdfJsonPathResolver(); + Path result = r.resolveEimIdfJsonFileFromPreferenceString(json.toString()); + Assertions.assertEquals(json.toAbsolutePath().normalize(), result.toAbsolutePath().normalize()); + } + + @Test + void nonexistent_custom_falls_back_to_default(@TempDir Path tempDir) + { + Path missing = tempDir.resolve("missing").resolve("eim_idf.json"); + EimIdfJsonPathResolver r = new EimIdfJsonPathResolver(); + Path result = r.resolveEimIdfJsonFileFromPreferenceString(missing.toString()); + Assertions.assertEquals(r.getDefaultEimIdfJsonFile(), result); + } + + @Test + void wrong_basename_falls_back_to_default(@TempDir Path tempDir) throws IOException + { + Path other = tempDir.resolve("other.json"); + Files.createFile(other); + EimIdfJsonPathResolver r = new EimIdfJsonPathResolver(); + Path result = r.resolveEimIdfJsonFileFromPreferenceString(other.toString()); + Assertions.assertEquals(r.getDefaultEimIdfJsonFile(), result); + } + + @Test + void path_that_is_not_regular_file_falls_back(@TempDir Path tempDir) throws IOException + { + Path asDir = tempDir.resolve("eim_idf.json"); + Files.createDirectories(asDir); + EimIdfJsonPathResolver r = new EimIdfJsonPathResolver(); + Path result = r.resolveEimIdfJsonFileFromPreferenceString(asDir.toString()); + Assertions.assertEquals(r.getDefaultEimIdfJsonFile(), result); + } +}