Skip to content

Commit c4e3627

Browse files
committed
Allow debug extensions to provide configurations to display in Select and Start Debugging
microsoft#88230
1 parent 155e563 commit c4e3627

4 files changed

Lines changed: 57 additions & 11 deletions

File tree

src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import { launchSchema, debuggersExtPoint, breakpointsExtPoint } from 'vs/workben
3232
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
3333
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
3434
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
35-
import { CancellationToken } from 'vs/base/common/cancellation';
35+
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
3636
import { withUndefinedAsNull } from 'vs/base/common/types';
3737
import { sequence } from 'vs/base/common/async';
3838
import { IHistoryService } from 'vs/workbench/services/history/common/history';
@@ -163,8 +163,8 @@ export class ConfigurationManager implements IConfigurationManager {
163163
return Promise.resolve(undefined);
164164
}
165165

166-
getDebuggerLabel(session: IDebugSession): string | undefined {
167-
const dbgr = this.getDebugger(session.configuration.type);
166+
getDebuggerLabel(type: string): string | undefined {
167+
const dbgr = this.getDebugger(type);
168168
if (dbgr) {
169169
return dbgr.label;
170170
}
@@ -246,11 +246,36 @@ export class ConfigurationManager implements IConfigurationManager {
246246
return results.reduce((first, second) => first.concat(second), []);
247247
}
248248

249-
async provideDynamicDebugConfigurations(folderUri: uri | undefined, type: string, token: CancellationToken): Promise<any[]> {
249+
async getDynamicProviders(): Promise<{ label: string, pick: () => Promise<{ launch: ILaunch, config: IConfig } | undefined> }[]> {
250250
await this.activateDebuggers('onDebugDynamicConfigurations');
251-
const results = await Promise.all(this.configProviders.filter(p => p.type === type && p.scope === DebugConfigurationProviderScope.Dynamic && p.provideDebugConfigurations).map(p => p.provideDebugConfigurations!(folderUri, token)));
251+
const dynamicProviders = this.configProviders.filter(p => p.scope === DebugConfigurationProviderScope.Dynamic && p.provideDebugConfigurations);
252+
return dynamicProviders.map(provider => {
253+
return {
254+
label: this.getDebuggerLabel(provider.type)!,
255+
pick: async () => {
256+
const token = new CancellationTokenSource();
257+
const picks: Promise<{ label: string, launch: ILaunch, config: IConfig }[]>[] = [];
258+
this.getLaunches().forEach(launch => {
259+
if (launch.workspace) {
260+
picks.push(provider.provideDebugConfigurations!(launch.workspace.uri, token.token).then(configurations => configurations.map(config => ({
261+
label: config.name,
262+
config,
263+
launch
264+
}))));
265+
}
266+
});
267+
const promiseOfPicks = Promise.all(picks).then(result => result.reduce((first, second) => first.concat(second), []));
252268

253-
return results.reduce((first, second) => first.concat(second), []);
269+
const result = await this.quickInputService.pick<{ label: string, launch: ILaunch, config: IConfig }>(promiseOfPicks, { placeHolder: nls.localize('selectConfiguration', "Select Debug Configuration") });
270+
if (!result) {
271+
// User canceled quick input we should notify the provider to cancel computing configurations
272+
token.cancel();
273+
}
274+
275+
return result;
276+
}
277+
};
278+
});
254279
}
255280

256281
getAllConfigurations(): { launch: ILaunch; name: string; presentation?: IConfigPresentation }[] {

src/vs/workbench/contrib/debug/browser/debugProgress.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export class DebugProgressContribution implements IWorkbenchContribution {
3535
});
3636

3737
this.progressService.withProgress({ location: VIEWLET_ID }, () => promise);
38-
const source = this.debugService.getConfigurationManager().getDebuggerLabel(session);
38+
const source = this.debugService.getConfigurationManager().getDebuggerLabel(session.configuration.type);
3939
this.progressService.withProgress({
4040
location: ProgressLocation.Notification,
4141
title: progressStartEvent.body.title,

src/vs/workbench/contrib/debug/browser/debugQuickAccess.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export class StartDebugQuickAccessProvider extends PickerQuickAccessProvider<IPi
2323
@IDebugService private readonly debugService: IDebugService,
2424
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
2525
@ICommandService private readonly commandService: ICommandService,
26-
@INotificationService private readonly notificationService: INotificationService
26+
@INotificationService private readonly notificationService: INotificationService,
2727
) {
2828
super(StartDebugQuickAccessProvider.PREFIX, {
2929
noResultsPick: {
@@ -32,8 +32,9 @@ export class StartDebugQuickAccessProvider extends PickerQuickAccessProvider<IPi
3232
});
3333
}
3434

35-
protected getPicks(filter: string): (IQuickPickSeparator | IPickerQuickAccessItem)[] {
35+
protected async getPicks(filter: string): Promise<(IQuickPickSeparator | IPickerQuickAccessItem)[]> {
3636
const picks: Array<IPickerQuickAccessItem | IQuickPickSeparator> = [];
37+
picks.push({ type: 'separator', label: 'launch.json' });
3738

3839
const configManager = this.debugService.getConfigurationManager();
3940

@@ -77,12 +78,31 @@ export class StartDebugQuickAccessProvider extends PickerQuickAccessProvider<IPi
7778
}
7879
}
7980

81+
// Entries detected configurations
82+
const dynamicProviders = await configManager.getDynamicProviders();
83+
if (dynamicProviders.length > 0) {
84+
picks.push({ type: 'separator', label: localize('contributed', "contributed") });
85+
}
86+
87+
dynamicProviders.forEach(provider => {
88+
picks.push({
89+
label: provider.label,
90+
accept: async () => {
91+
const pick = await provider.pick();
92+
if (pick) {
93+
this.debugService.startDebugging(pick.launch, pick.config);
94+
}
95+
},
96+
});
97+
});
98+
99+
80100
// Entries: launches
81101
const visibleLaunches = configManager.getLaunches().filter(launch => !launch.hidden);
82102

83103
// Separator
84104
if (visibleLaunches.length > 0) {
85-
picks.push({ type: 'separator' });
105+
picks.push({ type: 'separator', label: localize('configure', "configure") });
86106
}
87107

88108
for (const launch of visibleLaunches) {

src/vs/workbench/contrib/debug/common/debug.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,7 @@ export interface IConfigurationManager {
656656

657657
isDebuggerInterestedInLanguage(language: string): boolean;
658658
hasDebugConfigurationProvider(debugType: string): boolean;
659+
getDynamicProviders(): Promise<{ label: string, pick: () => Promise<{ launch: ILaunch, config: IConfig } | undefined> }[]>;
659660

660661
registerDebugConfigurationProvider(debugConfigurationProvider: IDebugConfigurationProvider): IDisposable;
661662
unregisterDebugConfigurationProvider(debugConfigurationProvider: IDebugConfigurationProvider): void;
@@ -665,7 +666,7 @@ export interface IConfigurationManager {
665666

666667
resolveConfigurationByProviders(folderUri: uri | undefined, type: string | undefined, debugConfiguration: any, token: CancellationToken): Promise<any>;
667668
getDebugAdapterDescriptor(session: IDebugSession): Promise<IAdapterDescriptor | undefined>;
668-
getDebuggerLabel(session: IDebugSession): string | undefined;
669+
getDebuggerLabel(type: string): string | undefined;
669670

670671
registerDebugAdapterFactory(debugTypes: string[], debugAdapterFactory: IDebugAdapterFactory): IDisposable;
671672
createDebugAdapter(session: IDebugSession): IDebugAdapter | undefined;

0 commit comments

Comments
 (0)