未验证 提交 fe66be12 编写于 作者: I Isidor Nikolic 提交者: GitHub

Merge pull request #100794 from microsoft/connor4312/allow-multiple-dynamic

debug: allow a single debug extension to provide multiple configs
......@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { dispose, IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { Event, Emitter } from 'vs/base/common/event';
import * as strings from 'vs/base/common/strings';
import * as objects from 'vs/base/common/objects';
......@@ -37,7 +37,7 @@ import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cance
import { withUndefinedAsNull } from 'vs/base/common/types';
import { sequence } from 'vs/base/common/async';
import { IHistoryService } from 'vs/workbench/services/history/common/history';
import { first } from 'vs/base/common/arrays';
import { first, flatten } from 'vs/base/common/arrays';
import { getVisibleAndSorted } from 'vs/workbench/contrib/debug/common/debugUtils';
import { DebugConfigurationProviderTriggerKind } from 'vs/workbench/api/common/extHostTypes';
......@@ -47,6 +47,8 @@ jsonRegistry.registerSchema(launchSchemaId, launchSchema);
const DEBUG_SELECTED_CONFIG_NAME_KEY = 'debug.selectedconfigname';
const DEBUG_SELECTED_ROOT = 'debug.selectedroot';
interface IDynamicPickItem { label: string, launch: ILaunch, config: IConfig }
export class ConfigurationManager implements IConfigurationManager {
private debuggers: Debugger[];
private breakpointModeIdsSet = new Set<string>();
......@@ -251,23 +253,60 @@ export class ConfigurationManager implements IConfigurationManager {
async getDynamicProviders(): Promise<{ label: string, pick: () => Promise<{ launch: ILaunch, config: IConfig } | undefined> }[]> {
const extensions = await this.extensionService.getExtensions();
const onDebugDynamicConfigurationsName = 'onDebugDynamicConfigurations';
const debugDynamicExtensionsTypes = extensions.map(e => {
const activationEvent = e.activationEvents && e.activationEvents.find(e => e.includes(onDebugDynamicConfigurationsName));
if (activationEvent) {
const type = activationEvent.substr(onDebugDynamicConfigurationsName.length + 1);
return type || (e.contributes && e.contributes.debuggers && e.contributes.debuggers.length ? e.contributes.debuggers[0].type : undefined);
const debugDynamicExtensionsTypes = extensions.reduce((acc, e) => {
if (!e.activationEvents) {
return acc;
}
return undefined;
}).filter(type => typeof type === 'string' && !!this.getDebuggerLabel(type)) as string[];
const explicitTypes: string[] = [];
let hasGenericEvent = false;
for (const event of e.activationEvents) {
if (event === onDebugDynamicConfigurationsName) {
hasGenericEvent = true;
} else if (event.startsWith(`${onDebugDynamicConfigurationsName}:`)) {
explicitTypes.push(event.slice(onDebugDynamicConfigurationsName.length + 1));
}
}
if (explicitTypes.length) {
return acc.concat(explicitTypes);
}
if (hasGenericEvent) {
const debuggerType = e.contributes?.debuggers?.[0].type;
return debuggerType ? acc.concat(debuggerType) : acc;
}
return acc;
}, [] as string[]);
return debugDynamicExtensionsTypes.map(type => {
return {
label: this.getDebuggerLabel(type)!,
pick: async () => {
const disposables = new DisposableStore();
const input = disposables.add(this.quickInputService.createQuickPick<IDynamicPickItem>());
input.busy = true;
input.placeholder = nls.localize('selectConfiguration', "Select Launch Configuration");
input.show();
let chosenDidCancel = false;
const chosenPromise = new Promise<IDynamicPickItem | undefined>(resolve => {
disposables.add(input.onDidAccept(() => resolve(input.activeItems[0])));
disposables.add(input.onDidTriggerItemButton(async (context) => {
resolve(undefined);
const { launch, config } = context.item;
await launch.openConfigFile(false, config.type);
// Only Launch have a pin trigger button
await (launch as Launch).writeConfiguration(config);
this.selectConfiguration(launch, config.name);
}));
disposables.add(input.onDidHide(() => { chosenDidCancel = true; resolve(); }));
});
await this.activateDebuggers(onDebugDynamicConfigurationsName, type);
const token = new CancellationTokenSource();
const picks: Promise<{ label: string, launch: ILaunch, config: IConfig }[]>[] = [];
const picks: Promise<IDynamicPickItem[]>[] = [];
const provider = this.configProviders.filter(p => p.type === type && p.triggerKind === DebugConfigurationProviderTriggerKind.Dynamic && p.provideDebugConfigurations)[0];
this.getLaunches().forEach(launch => {
if (launch.workspace && provider) {
......@@ -282,25 +321,30 @@ export class ConfigurationManager implements IConfigurationManager {
}))));
}
});
const promiseOfPicks = Promise.all(picks).then(result => result.reduce((first, second) => first.concat(second), []));
const result = await this.quickInputService.pick<{ label: string, launch: ILaunch, config: IConfig }>(promiseOfPicks, {
placeHolder: nls.localize('selectConfiguration', "Select Launch Configuration"),
onDidTriggerItemButton: async (context) => {
await this.quickInputService.cancel();
const { launch, config } = context.item;
await launch.openConfigFile(false, config.type);
// Only Launch have a pin trigger button
await (launch as Launch).writeConfiguration(config);
this.selectConfiguration(launch, config.name);
}
});
if (!result) {
const nestedPicks = await Promise.all(picks);
const items = flatten(nestedPicks);
let chosen: IDynamicPickItem | undefined;
// If there's exactly one item to choose from, pick it automatically
if (items.length === 1 && !chosenDidCancel) {
chosen = items[0];
} else {
input.items = items;
input.busy = false;
chosen = await chosenPromise;
}
disposables.dispose();
if (!chosen) {
// User canceled quick input we should notify the provider to cancel computing configurations
token.cancel();
return;
}
return result;
return chosen;
}
};
});
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册