Skip to content

Commit 494483e

Browse files
fedejeannemickaelistria
authored andcommitted
Make the "run/debug as..." menus run asynchronously
Make the calculation of ContextualLaunchAction::isApplicable run on a separate (non-UI) thread so that the UI remains responsive while it is being calculated. Once the calculation is done, an SWT.Show event is fired and the ActionContributionItem can react properly and update the menu.
1 parent dcabef0 commit 494483e

File tree

3 files changed

+112
-72
lines changed

3 files changed

+112
-72
lines changed

debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/DebugUIMessages.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,8 @@ public class DebugUIMessages extends NLS {
303303

304304
public static String LaunchShortcutAction_combineLaunchShortcutName;
305305

306+
public static String ContextualLaunchAction_0;
307+
306308
static {
307309
// load message values from bundle file
308310
NLS.initializeMessages(BUNDLE_NAME, DebugUIMessages.class);

debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/DebugUIMessages.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ CodePagesPrefDialog_7=ASCII codepage entered is invalid.
162162
CodePagesPrefDialog_8=Invalid codepage
163163
CodePagesPrefDialog_9=EBCDIC codepage entered is invalid.
164164
CodePagesPrefDialog_0=The codepage is not supported.
165+
ContextualLaunchAction_0=Loading...
165166

166167
##############################################################
167168
# View Tab

debug/org.eclipse.debug.ui/ui/org/eclipse/debug/ui/actions/ContextualLaunchAction.java

Lines changed: 109 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.Map;
2323
import java.util.Map.Entry;
2424
import java.util.Set;
25+
import java.util.concurrent.CompletableFuture;
2526

2627
import org.eclipse.core.expressions.Expression;
2728
import org.eclipse.core.expressions.IEvaluationContext;
@@ -50,6 +51,8 @@
5051
import org.eclipse.swt.events.MenuAdapter;
5152
import org.eclipse.swt.events.MenuEvent;
5253
import org.eclipse.swt.widgets.Control;
54+
import org.eclipse.swt.widgets.Display;
55+
import org.eclipse.swt.widgets.Event;
5356
import org.eclipse.swt.widgets.Menu;
5457
import org.eclipse.swt.widgets.MenuItem;
5558
import org.eclipse.ui.IEditorPart;
@@ -205,92 +208,126 @@ protected void fillMenu(Menu menu) {
205208
}
206209
List<Object> selection = ss.toList();
207210
Object o = ss.getFirstElement();
208-
IEditorPart editor = null;
211+
final IEditorPart editor;
209212
if(o instanceof IEditorPart editorPart) {
210213
editor = editorPart;
211214
selection.set(0, editorPart.getEditorInput());
215+
} else {
216+
editor = null;
212217
}
218+
213219
IEvaluationContext context = DebugUIPlugin.createEvaluationContext(selection);
214220
context.setAllowPluginActivation(true);
215221
context.addVariable("selection", selection); //$NON-NLS-1$
222+
223+
MenuItem loadingItem = new MenuItem(menu, SWT.NONE);
224+
loadingItem.setText(DebugUIMessages.ContextualLaunchAction_0);
225+
loadingItem.setEnabled(false);
226+
227+
final int finalAcc = accelerator;
228+
CompletableFuture.supplyAsync(() -> filterShortcuts(context))// filtering can be a long-running operation
229+
.thenAccept(filteredShortcuts -> {
230+
231+
// Run this in the UI thread so the menu can be populated
232+
Display.getDefault().syncExec(() -> {
233+
234+
int internalAccelerator = finalAcc;
235+
// replace "Loading..." with actual stuff
236+
loadingItem.dispose();
237+
238+
// we need a separator iff the shared config entry has been added and there are
239+
// following shortcuts
240+
if (menu.getItemCount() > 0 && filteredShortcuts.size() > 0) {
241+
new MenuItem(menu, SWT.SEPARATOR);
242+
}
243+
244+
List<String> categories = new ArrayList<>();
245+
Map<LaunchShortcutExtension, ILaunchConfiguration[]> launchConfigurations = new LinkedHashMap<>();
246+
for (LaunchShortcutExtension ext : filteredShortcuts) {
247+
for (String mode : ext.getModes()) {
248+
if (mode.equals(fMode)) {
249+
String category = ext.getCategory();
250+
// NOTE: category can be null
251+
if (category != null && !categories.contains(category)) {
252+
categories.add(category);
253+
}
254+
populateMenuItem(mode, ext, menu, null, internalAccelerator++, null);
255+
ILaunchConfiguration[] configurations = editor != null
256+
? ext.getLaunchConfigurations(editor)
257+
: ext.getLaunchConfigurations(ss);
258+
if (configurations != null) {
259+
launchConfigurations.put(ext, configurations);
260+
}
261+
}
262+
}
263+
}
264+
265+
// add in the open ... dialog shortcut(s)
266+
if (categories.isEmpty()) {
267+
if (internalAccelerator > 1) {
268+
new MenuItem(menu, SWT.SEPARATOR);
269+
}
270+
IAction action = new OpenLaunchDialogAction(fGroup.getIdentifier());
271+
ActionContributionItem item = new ActionContributionItem(action);
272+
item.fill(menu, -1);
273+
} else {
274+
boolean addedSep = false;
275+
for (String category : categories) {
276+
ILaunchGroup group = fGroup;
277+
if (category != null) {
278+
group = fGroupsByCategory.get(category);
279+
}
280+
if (group != null) {
281+
if (internalAccelerator > 1 && !addedSep) {
282+
new MenuItem(menu, SWT.SEPARATOR);
283+
addedSep = true;
284+
}
285+
IAction action = new OpenLaunchDialogAction(group.getIdentifier());
286+
ActionContributionItem item= new ActionContributionItem(action);
287+
item.fill(menu, -1);
288+
}
289+
}
290+
}
291+
292+
// now add collected launches
293+
Set<ILaunchConfiguration> added = new HashSet<>();
294+
for (Entry<LaunchShortcutExtension, ILaunchConfiguration[]> entry : launchConfigurations.entrySet()) {
295+
for (ILaunchConfiguration configuration : entry.getValue()) {
296+
if (added.add(configuration)) {
297+
populateMenuItem(fMode, entry.getKey(), menu, configuration, internalAccelerator++,
298+
null);
299+
}
300+
}
301+
}
302+
303+
// update UI
304+
Event event = new Event();
305+
event.data = menu;
306+
menu.notifyListeners(SWT.Show, event);
307+
308+
fFillMenu = false;
309+
});
310+
});
311+
}
312+
313+
private List<LaunchShortcutExtension> filterShortcuts(IEvaluationContext context) {
216314
List<LaunchShortcutExtension> allShortCuts = getLaunchConfigurationManager().getLaunchShortcuts();
217315
List<LaunchShortcutExtension> filteredShortCuts = new ArrayList<>();
218-
Iterator<LaunchShortcutExtension> iter = allShortCuts.iterator();
219-
while (iter.hasNext()) {
220-
LaunchShortcutExtension ext = iter.next();
316+
Iterator<LaunchShortcutExtension> allShortcutsIter = allShortCuts.iterator();
317+
while (allShortcutsIter.hasNext()) {
318+
LaunchShortcutExtension shortcut = allShortcutsIter.next();
221319
try {
222-
if (!WorkbenchActivityHelper.filterItem(ext) && isApplicable(ext, context)) {
223-
filteredShortCuts.add(ext);
320+
if (!WorkbenchActivityHelper.filterItem(shortcut) && isApplicable(shortcut, context)) {
321+
filteredShortCuts.add(shortcut);
224322
}
225-
}
226-
catch (CoreException e) {
227-
IStatus status = new Status(IStatus.ERROR, DebugUIPlugin.getUniqueIdentifier(), "Launch shortcut '" + ext.getId() + "' enablement expression caused exception. Shortcut was removed.", e); //$NON-NLS-1$ //$NON-NLS-2$
323+
} catch (CoreException e) {
324+
IStatus status = new Status(IStatus.ERROR, DebugUIPlugin.getUniqueIdentifier(), "Launch shortcut '" //$NON-NLS-1$
325+
+ shortcut.getId() + "' enablement expression caused exception. Shortcut was removed.", e); //$NON-NLS-1$
228326
DebugUIPlugin.log(status);
229-
iter.remove();
230-
}
231-
}
232-
233-
//we need a separator iff the shared config entry has been added and there are following shortcuts
234-
if(menu.getItemCount() > 0 && filteredShortCuts.size() > 0) {
235-
new MenuItem(menu, SWT.SEPARATOR);
236-
}
237-
List<String> categories = new ArrayList<>();
238-
Map<LaunchShortcutExtension, ILaunchConfiguration[]> launchConfigurations = new LinkedHashMap<>();
239-
for(LaunchShortcutExtension ext : filteredShortCuts) {
240-
for(String mode : ext.getModes()) {
241-
if (mode.equals(fMode)) {
242-
String category = ext.getCategory();
243-
// NOTE: category can be null
244-
if (category != null && !categories.contains(category)) {
245-
categories.add(category);
246-
}
247-
populateMenuItem(mode, ext, menu, null, accelerator++, null);
248-
ILaunchConfiguration[] configurations = editor != null ?
249-
ext.getLaunchConfigurations(editor) :
250-
ext.getLaunchConfigurations(ss);
251-
if (configurations != null) {
252-
launchConfigurations.put(ext, configurations);
253-
}
254-
}
255-
}
256-
}
257-
258-
// add in the open ... dialog shortcut(s)
259-
if (categories.isEmpty()) {
260-
if (accelerator > 1) {
261-
new MenuItem(menu, SWT.SEPARATOR);
262-
}
263-
IAction action = new OpenLaunchDialogAction(fGroup.getIdentifier());
264-
ActionContributionItem item = new ActionContributionItem(action);
265-
item.fill(menu, -1);
266-
} else {
267-
boolean addedSep = false;
268-
for (String category : categories) {
269-
ILaunchGroup group = fGroup;
270-
if (category != null) {
271-
group = fGroupsByCategory.get(category);
272-
}
273-
if (group != null) {
274-
if (accelerator > 1 && !addedSep) {
275-
new MenuItem(menu, SWT.SEPARATOR);
276-
addedSep = true;
277-
}
278-
IAction action = new OpenLaunchDialogAction(group.getIdentifier());
279-
ActionContributionItem item= new ActionContributionItem(action);
280-
item.fill(menu, -1);
281-
}
327+
allShortcutsIter.remove();
282328
}
283329
}
284-
// now add collected launches
285-
Set<ILaunchConfiguration> added = new HashSet<>();
286-
for (Entry<LaunchShortcutExtension, ILaunchConfiguration[]> entry : launchConfigurations.entrySet()) {
287-
for (ILaunchConfiguration configuration : entry.getValue()) {
288-
if (added.add(configuration)) {
289-
populateMenuItem(fMode, entry.getKey(), menu, configuration, accelerator++, null);
290-
}
291-
}
292-
}
293-
330+
return filteredShortCuts;
294331
}
295332

296333
/**

0 commit comments

Comments
 (0)