diff --git a/bundles/com.espressif.idf.ui/plugin.xml b/bundles/com.espressif.idf.ui/plugin.xml
index ba3542ed2..f14736fcb 100644
--- a/bundles/com.espressif.idf.ui/plugin.xml
+++ b/bundles/com.espressif.idf.ui/plugin.xml
@@ -521,6 +521,21 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/LaunchBarListener.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/LaunchBarListener.java
index 983d8271d..5d79ef522 100644
--- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/LaunchBarListener.java
+++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/LaunchBarListener.java
@@ -51,7 +51,7 @@ public static void setIgnoreTargetChange(boolean status)
@Override
public void activeLaunchTargetChanged(ILaunchTarget target)
{
- Display.getDefault().asyncExec(() -> {
+ Display.getDefault().syncExec(() -> {
if (target != null)
{
String targetName = target.getAttribute("com.espressif.idf.launch.serial.core.idfTarget", //$NON-NLS-1$
diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/dialogs/Messages.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/dialogs/Messages.java
index 54eb9de7d..113455edb 100644
--- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/dialogs/Messages.java
+++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/dialogs/Messages.java
@@ -28,6 +28,12 @@ public class Messages extends NLS
public static String HintDetailsTitle;
public static String FilterMessage;
public static String HintsYmlNotFoundErrMsg;
+ public static String SelectDebugConfigDialog_LableText;
+ public static String SelectDebugConfigDialog_Text;
+ public static String SelectDebugConfigDialog_Title;
+ public static String SelectLaunchConfigDialog_LableText;
+ public static String SelectLaunchConfigDialog_Text;
+ public static String SelectLaunchConfigDialog_Title;
public static String WriteFlashDialog_Bin_Path_Lbl;
public static String WriteFlashDialog_BinFileErrFormatErrMsg;
public static String WriteFlashDialog_Browse_Btn;
diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/dialogs/SelectDebugConfigDialog.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/dialogs/SelectDebugConfigDialog.java
new file mode 100644
index 000000000..ae6649032
--- /dev/null
+++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/dialogs/SelectDebugConfigDialog.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright 2024-2025 Espressif Systems (Shanghai) PTE LTD. All rights reserved.
+ * Use is subject to license terms.
+ *******************************************************************************/
+package com.espressif.idf.ui.dialogs;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.launchbar.core.ILaunchBarManager;
+import org.eclipse.launchbar.core.ILaunchDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+
+import com.espressif.idf.core.logging.Logger;
+import com.espressif.idf.ui.UIPlugin;
+
+public class SelectDebugConfigDialog extends TitleAreaDialog
+{
+
+ private Combo descriptorsCombo;
+ private final List suitableConfiguratios;
+
+ public SelectDebugConfigDialog(Shell parentShell, List suitableConfiguratios)
+ {
+ super(parentShell);
+ this.suitableConfiguratios = suitableConfiguratios;
+ }
+
+ @Override
+ public void create()
+ {
+ super.create();
+ setTitle(Messages.SelectDebugConfigDialog_Title);
+ setMessage(Messages.SelectDebugConfigDialog_Text, IMessageProvider.INFORMATION);
+ }
+
+ @Override
+ protected void configureShell(Shell newShell)
+ {
+ super.configureShell(newShell);
+ newShell.setText(Messages.SelectDebugConfigDialog_Title);
+ }
+
+ @Override
+ protected void createButtonsForButtonBar(Composite parent)
+ {
+ // create OK and Cancel buttons by default
+ createButton(parent, IDialogConstants.OK_ID, "Debug", true); //$NON-NLS-1$
+ createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent)
+ {
+ Composite area = (Composite) super.createDialogArea(parent);
+ Composite container = new Composite(area, SWT.NONE);
+ container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ GridLayout layout = new GridLayout(2, false);
+ container.setLayout(layout);
+
+ Label descriptorsLabel = new Label(container, SWT.NONE);
+ descriptorsLabel.setText(Messages.SelectDebugConfigDialog_LableText);
+
+ GridData comboLayoutData = new GridData();
+ comboLayoutData.grabExcessHorizontalSpace = true;
+ comboLayoutData.horizontalAlignment = GridData.FILL;
+ comboLayoutData.horizontalSpan = 1;
+
+ descriptorsCombo = new Combo(container, SWT.READ_ONLY);
+ descriptorsCombo.setItems(suitableConfiguratios.toArray(new String[0]));
+ descriptorsCombo.select(0);
+ descriptorsCombo.setLayoutData(comboLayoutData);
+ return super.createDialogArea(parent);
+ }
+
+ @Override
+ protected void okPressed()
+ {
+ ILaunchBarManager launchBarManager = UIPlugin.getService(ILaunchBarManager.class);
+ try
+ {
+ ILaunchDescriptor[] descriptors = launchBarManager.getLaunchDescriptors();
+ Optional optDisc = Stream.of(descriptors)
+ .filter(disc -> disc.getName().contentEquals(descriptorsCombo.getText())).findFirst();
+ if (optDisc.isPresent())
+ {
+ launchBarManager.setActiveLaunchDescriptor(optDisc.get());
+ }
+
+ }
+ catch (CoreException e)
+ {
+ Logger.log(e);
+ }
+
+ super.okPressed();
+ }
+
+}
diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/dialogs/SelectLaunchConfigDialog.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/dialogs/SelectLaunchConfigDialog.java
new file mode 100644
index 000000000..7f657060e
--- /dev/null
+++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/dialogs/SelectLaunchConfigDialog.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright 2024-2025 Espressif Systems (Shanghai) PTE LTD. All rights reserved.
+ * Use is subject to license terms.
+ *******************************************************************************/
+package com.espressif.idf.ui.dialogs;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.launchbar.core.ILaunchBarManager;
+import org.eclipse.launchbar.core.ILaunchDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+
+import com.espressif.idf.core.logging.Logger;
+import com.espressif.idf.ui.UIPlugin;
+
+public class SelectLaunchConfigDialog extends TitleAreaDialog
+{
+ private Combo descriptorsCombo;
+ private final List suitableConfiguratios;
+
+ public SelectLaunchConfigDialog(Shell parentShell, List suitableConfiguratios)
+ {
+ super(parentShell);
+ this.suitableConfiguratios = suitableConfiguratios;
+ }
+
+ @Override
+ protected void configureShell(Shell newShell)
+ {
+ super.configureShell(newShell);
+ newShell.setText(Messages.SelectLaunchConfigDialog_Title);
+ }
+
+ @Override
+ public void create()
+ {
+ super.create();
+ setTitle(Messages.SelectLaunchConfigDialog_Title);
+ setMessage(Messages.SelectLaunchConfigDialog_Text, IMessageProvider.INFORMATION);
+ }
+
+ @Override
+ protected void createButtonsForButtonBar(Composite parent)
+ {
+ // create OK and Cancel buttons by default
+ createButton(parent, IDialogConstants.OK_ID, "Launch", true); //$NON-NLS-1$
+ createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent)
+ {
+ Composite area = (Composite) super.createDialogArea(parent);
+ Composite container = new Composite(area, SWT.NONE);
+ container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ GridLayout layout = new GridLayout(2, false);
+ container.setLayout(layout);
+
+ Label descriptorsLabel = new Label(container, SWT.NONE);
+ descriptorsLabel.setText(Messages.SelectLaunchConfigDialog_LableText);
+
+ GridData comboLayoutData = new GridData();
+ comboLayoutData.grabExcessHorizontalSpace = true;
+ comboLayoutData.horizontalAlignment = GridData.FILL;
+ comboLayoutData.horizontalSpan = 1;
+
+ descriptorsCombo = new Combo(container, SWT.READ_ONLY);
+ descriptorsCombo.setItems(suitableConfiguratios.toArray(new String[0]));
+ descriptorsCombo.select(0);
+ descriptorsCombo.setLayoutData(comboLayoutData);
+ return super.createDialogArea(parent);
+ }
+
+ @Override
+ protected void okPressed()
+ {
+ ILaunchBarManager launchBarManager = UIPlugin.getService(ILaunchBarManager.class);
+ try
+ {
+ ILaunchDescriptor[] descriptors = launchBarManager.getLaunchDescriptors();
+ Optional optDisc = Stream.of(descriptors)
+ .filter(disc -> disc.getName().contentEquals(descriptorsCombo.getText())).findFirst();
+ if (optDisc.isPresent())
+ {
+ launchBarManager.setActiveLaunchDescriptor(optDisc.get());
+ }
+
+ }
+ catch (CoreException e)
+ {
+ Logger.log(e);
+ }
+
+ super.okPressed();
+ }
+
+}
diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/dialogs/messages.properties b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/dialogs/messages.properties
index 6695fbc8a..c8a637331 100644
--- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/dialogs/messages.properties
+++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/dialogs/messages.properties
@@ -21,6 +21,12 @@ DeleteResourcesWizard_project_deleteConfigurations=Delete all related configurat
HintDetailsTitle=Hint Details
FilterMessage=type filter text
HintsYmlNotFoundErrMsg={0} is missing. Hints are only supported from esp-idf v5.0 and higher
+SelectDebugConfigDialog_LableText=Suitable Debug Configurations:
+SelectDebugConfigDialog_Text=To debug a project, the Debug Configuration should be selected. Select a Debug Configuration and click "Debug"
+SelectDebugConfigDialog_Title=Select Debug Configuration
+SelectLaunchConfigDialog_LableText=Suitable Launch Configurations:
+SelectLaunchConfigDialog_Text=To launch a project, the Launch Configuration should be selected. Select a Launch Configuration and click "Launch"
+SelectLaunchConfigDialog_Title=Select Launch Configuration
WriteFlashDialog_Bin_Path_Lbl=Bin Path:
WriteFlashDialog_BinFileErrFormatErrMsg=%s bin file doens't exist
WriteFlashDialog_Browse_Btn=Browse
diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/handlers/Messages.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/handlers/Messages.java
index 79c542845..0552d3a2e 100644
--- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/handlers/Messages.java
+++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/handlers/Messages.java
@@ -20,6 +20,11 @@ public class Messages extends NLS
public static String UpdateEspIdfCommand_JobMsg;
public static String UpdateEspIdfCommand_InstallToolsJobMsg;
public static String UpdateEspIdfCommand_SuggestToOpenInstallToolsWizard;
+ public static String MissingDebugConfigurationTitle;
+ public static String DebugConfigurationNotFoundMsg;
+
+ public static String RunActionHandler_NoProjectQuestionText;
+ public static String RunActionHandler_NoProjectQuestionTitle;
static
{
diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/handlers/RunActionHandler.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/handlers/RunActionHandler.java
new file mode 100644
index 000000000..805a9aa32
--- /dev/null
+++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/handlers/RunActionHandler.java
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ * Copyright 2024-2025 Espressif Systems (Shanghai) PTE LTD. All rights reserved.
+ * Use is subject to license terms.
+ *******************************************************************************/
+package com.espressif.idf.ui.handlers;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.debug.core.ILaunchMode;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.window.Window;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.launchbar.core.ILaunchBarManager;
+import org.eclipse.launchbar.ui.ILaunchBarUIManager;
+import org.eclipse.launchbar.ui.NewLaunchConfigWizard;
+import org.eclipse.launchbar.ui.NewLaunchConfigWizardDialog;
+import org.eclipse.launchbar.ui.internal.commands.LaunchActiveCommandHandler;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+import com.espressif.idf.core.build.IDFLaunchConstants;
+import com.espressif.idf.core.logging.Logger;
+import com.espressif.idf.core.util.StringUtil;
+import com.espressif.idf.ui.UIPlugin;
+import com.espressif.idf.ui.dialogs.SelectDebugConfigDialog;
+import com.espressif.idf.ui.dialogs.SelectLaunchConfigDialog;
+
+@SuppressWarnings("restriction")
+public class RunActionHandler extends LaunchActiveCommandHandler
+{
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+ try
+ {
+ ILaunchBarManager launchBarManager = UIPlugin.getService(ILaunchBarManager.class);
+ new StopLaunchBuildHandler().stop();
+ ILaunchConfiguration config = launchBarManager.getActiveLaunchConfiguration();
+ if (config == null)
+ {
+ return Status.OK_STATUS;
+ }
+
+ ILaunchMode launchMode = launchBarManager.getActiveLaunchMode();
+ if (launchMode == null)
+ {
+ return Status.OK_STATUS;
+ }
+ int returnCode = Window.OK;
+ String projectName = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME,
+ StringUtil.EMPTY);
+ if (projectName.isBlank())
+ {
+ Boolean isYes = MessageDialog.openQuestion(Display.getDefault().getActiveShell(),
+ Messages.RunActionHandler_NoProjectQuestionTitle,
+ Messages.RunActionHandler_NoProjectQuestionText);
+ if (isYes)
+ {
+ ILaunchBarUIManager uiManager = UIPlugin.getService(ILaunchBarUIManager.class);
+ uiManager.openConfigurationEditor(launchBarManager.getActiveLaunchDescriptor());
+ }
+ return Status.CANCEL_STATUS;
+ }
+ if (launchMode.getIdentifier().equals(ILaunchManager.DEBUG_MODE)
+ && config.getType().getIdentifier().contentEquals(IDFLaunchConstants.RUN_LAUNCH_CONFIG_TYPE))
+ {
+ List suitableDescNames = findSuitableDescNames(projectName,
+ IDFLaunchConstants.DEBUG_LAUNCH_CONFIG_TYPE);
+ if (suitableDescNames.isEmpty())
+ {
+ showMessage(Messages.DebugConfigurationNotFoundMsg);
+ return Status.CANCEL_STATUS;
+ }
+ returnCode = new SelectDebugConfigDialog(Display.getDefault().getActiveShell(), suitableDescNames)
+ .open();
+ }
+ else if (launchMode.getIdentifier().equals(ILaunchManager.RUN_MODE)
+ && config.getType().getIdentifier().contentEquals(IDFLaunchConstants.DEBUG_LAUNCH_CONFIG_TYPE))
+ {
+ List suitableDescNames = findSuitableDescNames(projectName,
+ IDFLaunchConstants.RUN_LAUNCH_CONFIG_TYPE);
+ returnCode = new SelectLaunchConfigDialog(Display.getDefault().getActiveShell(), suitableDescNames)
+ .open();
+ }
+ if (returnCode == Window.OK)
+ {
+ launchBarManager.setActiveLaunchMode(launchMode);
+ config = launchBarManager.getActiveLaunchConfiguration();
+ DebugUITools.launch(config, launchMode.getIdentifier());
+ }
+
+ return Status.OK_STATUS;
+ }
+ catch (CoreException e)
+ {
+ return e.getStatus();
+ }
+ }
+
+ private List findSuitableDescNames(String projectName, String configType)
+ {
+ ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
+ List configList = new ArrayList<>();
+ try
+ {
+ configList = Arrays.asList(
+ launchManager.getLaunchConfigurations(launchManager.getLaunchConfigurationType(configType)));
+
+ }
+ catch (CoreException e)
+ {
+ Logger.log(e);
+ }
+ return configList.stream().filter(config -> {
+ try
+ {
+ return config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, StringUtil.EMPTY)
+ .contentEquals(projectName);
+ }
+ catch (CoreException e)
+ {
+ Logger.log(e);
+ }
+ return false;
+ }).map(config -> config.getName()).collect(Collectors.toList());
+ }
+
+ private void showMessage(final String message)
+ {
+ Display.getDefault().asyncExec(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ Shell activeShell = Display.getDefault().getActiveShell();
+ boolean isYes = MessageDialog.openQuestion(activeShell, Messages.MissingDebugConfigurationTitle,
+ message);
+ if (isYes)
+ {
+
+ NewLaunchConfigWizard wizard = new NewLaunchConfigWizard();
+ WizardDialog dialog = new NewLaunchConfigWizardDialog(activeShell, wizard);
+ dialog.open();
+ try
+ {
+ wizard.getWorkingCopy().doSave();
+ }
+ catch (CoreException e)
+ {
+ Logger.log(e);
+ }
+ }
+ }
+ });
+ }
+}
diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/handlers/messages.properties b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/handlers/messages.properties
index 7d487ae6f..69c0d3a4a 100644
--- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/handlers/messages.properties
+++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/handlers/messages.properties
@@ -12,4 +12,8 @@ PythonCleanCommandHandler_RunningPythonCleanJobName=Running python-clean command
StopLaunchBuildHandler_0=Stopping build
UpdateEspIdfCommand_JobMsg=Updating ESP-IDF master...
UpdateEspIdfCommand_InstallToolsJobMsg=Installing tools...
-UpdateEspIdfCommand_SuggestToOpenInstallToolsWizard = A new set of tools might be required to install. Do you want to open the Install Tools dialog?
\ No newline at end of file
+UpdateEspIdfCommand_SuggestToOpenInstallToolsWizard = A new set of tools might be required to install. Do you want to open the Install Tools dialog?
+MissingDebugConfigurationTitle=Missing debug configuration
+DebugConfigurationNotFoundMsg=No matching debug configuration was found for the selected project. Do you want to create it?
+RunActionHandler_NoProjectQuestionText=The selected configuration does not include a project. Would you like to edit the active launch configuration and specify the project?
+RunActionHandler_NoProjectQuestionTitle=Edit Active Configuration?