Skip to content

Commit

Permalink
debug: dynamic launch configurations should be stored properly
Browse files Browse the repository at this point in the history
fixes #96293
  • Loading branch information
isidorn committed Sep 8, 2020
1 parent 89a2e78 commit b1a66b5
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 16 deletions.
10 changes: 5 additions & 5 deletions src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { SelectBox, ISelectOptionItem } from 'vs/base/browser/ui/selectBox/selectBox';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IDebugService, IDebugSession, IDebugConfiguration, IConfig, ILaunch } from 'vs/workbench/contrib/debug/common/debug';
import { IDebugService, IDebugSession, IDebugConfiguration, IConfig, ILaunch, IDebugConfigurationProvider } from 'vs/workbench/contrib/debug/common/debug';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { attachSelectBoxStyler, attachStylerCallback } from 'vs/platform/theme/common/styler';
import { selectBorder, selectBackground } from 'vs/platform/theme/common/colorRegistry';
Expand All @@ -34,7 +34,7 @@ export class StartDebugActionViewItem implements IActionViewItem {
private options: { label: string, handler: (() => Promise<boolean>) }[] = [];
private toDispose: IDisposable[];
private selected = 0;
private providers: { label: string, pick: () => Promise<{ launch: ILaunch, config: IConfig } | undefined> }[] = [];
private providers: { label: string, provider: IDebugConfigurationProvider, pick: () => Promise<{ launch: ILaunch, config: IConfig } | undefined> }[] = [];

constructor(
private context: unknown,
Expand Down Expand Up @@ -182,7 +182,7 @@ export class StartDebugActionViewItem implements IActionViewItem {
const label = inWorkspace ? `${name} (${launch.name})` : name;
this.options.push({
label, handler: async () => {
manager.selectConfiguration(launch, name);
await manager.selectConfiguration(launch, name);
return true;
}
});
Expand All @@ -196,15 +196,15 @@ export class StartDebugActionViewItem implements IActionViewItem {
}

this.providers.forEach(p => {
if (p.label === manager.selectedConfiguration.name) {
if (p.provider.type === manager.selectedConfiguration.config?.type) {
this.selected = this.options.length;
}

this.options.push({
label: `${p.label}...`, handler: async () => {
const picked = await p.pick();
if (picked) {
manager.selectConfiguration(picked.launch, p.label, picked.config);
await manager.selectConfiguration(picked.launch, picked.config.name, picked.config);
return true;
}
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ jsonRegistry.registerSchema(launchSchemaId, launchSchema);

const DEBUG_SELECTED_CONFIG_NAME_KEY = 'debug.selectedconfigname';
const DEBUG_SELECTED_ROOT = 'debug.selectedroot';
// Debug type is only stored if a dynamic configuration is used for better restore
const DEBUG_SELECTED_TYPE = 'debug.selectedtype';

interface IDynamicPickItem { label: string, launch: ILaunch, config: IConfig }

Expand Down Expand Up @@ -84,13 +86,15 @@ export class ConfigurationManager implements IConfigurationManager {
this.initLaunches();
this.registerListeners();
const previousSelectedRoot = this.storageService.get(DEBUG_SELECTED_ROOT, StorageScope.WORKSPACE);
const previousSelectedType = this.storageService.get(DEBUG_SELECTED_TYPE, StorageScope.WORKSPACE);
const previousSelectedLaunch = this.launches.find(l => l.uri.toString() === previousSelectedRoot);
const previousSelectedName = this.storageService.get(DEBUG_SELECTED_CONFIG_NAME_KEY, StorageScope.WORKSPACE);
this.debugConfigurationTypeContext = CONTEXT_DEBUG_CONFIGURATION_TYPE.bindTo(contextKeyService);
this.debuggersAvailable = CONTEXT_DEBUGGERS_AVAILABLE.bindTo(contextKeyService);
if (previousSelectedLaunch && previousSelectedLaunch.getConfigurationNames().length) {
this.selectConfiguration(previousSelectedLaunch, this.storageService.get(DEBUG_SELECTED_CONFIG_NAME_KEY, StorageScope.WORKSPACE));
this.selectConfiguration(previousSelectedLaunch, previousSelectedName, undefined, previousSelectedType);
} else if (this.launches.length > 0) {
this.selectConfiguration(undefined);
this.selectConfiguration(undefined, previousSelectedName, undefined, previousSelectedType);
}
}

Expand Down Expand Up @@ -259,7 +263,7 @@ export class ConfigurationManager implements IConfigurationManager {
return results.reduce((first, second) => first.concat(second), []);
}

async getDynamicProviders(): Promise<{ label: string, pick: () => Promise<{ launch: ILaunch, config: IConfig } | undefined> }[]> {
async getDynamicProviders(): Promise<{ label: string, provider: IDebugConfigurationProvider, pick: () => Promise<{ launch: ILaunch, config: IConfig } | undefined> }[]> {
const extensions = await this.extensionService.getExtensions();
const onDebugDynamicConfigurationsName = 'onDebugDynamicConfigurations';
const debugDynamicExtensionsTypes = extensions.reduce((acc, e) => {
Expand Down Expand Up @@ -289,9 +293,12 @@ export class ConfigurationManager implements IConfigurationManager {
return acc;
}, [] as string[]);

await Promise.all(debugDynamicExtensionsTypes.map(type => this.activateDebuggers(onDebugDynamicConfigurationsName, type)));
return debugDynamicExtensionsTypes.map(type => {
const provider = this.configProviders.find(p => p.type === type && p.triggerKind === DebugConfigurationProviderTriggerKind.Dynamic && p.provideDebugConfigurations)!;
return {
label: this.getDebuggerLabel(type)!,
provider,
pick: async () => {
const disposables = new DisposableStore();
const input = disposables.add(this.quickInputService.createQuickPick<IDynamicPickItem>());
Expand All @@ -308,15 +315,13 @@ export class ConfigurationManager implements IConfigurationManager {
await launch.openConfigFile(false, config.type);
// Only Launch have a pin trigger button
await (launch as Launch).writeConfiguration(config);
this.selectConfiguration(launch, config.name);
await this.selectConfiguration(launch, config.name);
}));
disposables.add(input.onDidHide(() => { chosenDidCancel = true; resolve(); }));
});

await this.activateDebuggers(onDebugDynamicConfigurationsName, type);
const token = new CancellationTokenSource();
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) {
picks.push(provider.provideDebugConfigurations!(launch.workspace.uri, token.token).then(configurations => configurations.map(config => ({
Expand Down Expand Up @@ -508,7 +513,7 @@ export class ConfigurationManager implements IConfigurationManager {
return undefined;
}

selectConfiguration(launch: ILaunch | undefined, name?: string, config?: IConfig): void {
async selectConfiguration(launch: ILaunch | undefined, name?: string, config?: IConfig, type?: string): Promise<void> {
if (typeof launch === 'undefined') {
const rootUri = this.historyService.getLastActiveWorkspaceRoot();
launch = this.getLaunch(rootUri);
Expand All @@ -526,14 +531,31 @@ export class ConfigurationManager implements IConfigurationManager {
} else {
this.storageService.remove(DEBUG_SELECTED_ROOT, StorageScope.WORKSPACE);
}

const names = launch ? launch.getConfigurationNames() : [];
if ((name && names.indexOf(name) >= 0) || config) {
this.setSelectedLaunchName(name);
} else if (!this.selectedName || names.indexOf(this.selectedName) === -1) {
this.setSelectedLaunchName(names.length ? names[0] : undefined);
// We could not find the previously used name. We should get all dynamic configurations from providers
// And potentially auto select the previously used dynamic configuration #96293
const providers = await this.getDynamicProviders();
const provider = providers.find(p => p.provider.type === type);
let nameToSet = names.length ? names[0] : undefined;
if (provider && launch && launch.workspace) {
const token = new CancellationTokenSource();
const dynamicConfigs = await provider.provider.provideDebugConfigurations!(launch.workspace.uri, token.token);
const dynamicConfig = dynamicConfigs.find(c => c.name === name);
if (dynamicConfig) {
config = dynamicConfig;
nameToSet = name;
}
}

this.setSelectedLaunchName(nameToSet);
}

this.selectedConfig = config;
this.storageService.store(DEBUG_SELECTED_TYPE, this.selectedConfig?.type, StorageScope.WORKSPACE);
const configForType = this.selectedConfig || (this.selectedLaunch && this.selectedName ? this.selectedLaunch.getConfiguration(this.selectedName) : undefined);
if (configForType) {
this.debugConfigurationTypeContext.set(configForType.type);
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/contrib/debug/browser/debugQuickAccess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export class StartDebugQuickAccessProvider extends PickerQuickAccessProvider<IPi
return TriggerAction.CLOSE_PICKER;
},
accept: async () => {
this.debugService.getConfigurationManager().selectConfiguration(config.launch, config.name);
await this.debugService.getConfigurationManager().selectConfiguration(config.launch, config.name);
try {
await this.debugService.startDebugging(config.launch);
} catch (error) {
Expand Down
4 changes: 2 additions & 2 deletions src/vs/workbench/contrib/debug/common/debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -671,7 +671,7 @@ export interface IConfigurationManager {
name: string | undefined;
};

selectConfiguration(launch: ILaunch | undefined, name?: string, config?: IConfig): void;
selectConfiguration(launch: ILaunch | undefined, name?: string, config?: IConfig): Promise<void>;

getLaunches(): ReadonlyArray<ILaunch>;

Expand All @@ -692,7 +692,7 @@ export interface IConfigurationManager {

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

registerDebugConfigurationProvider(debugConfigurationProvider: IDebugConfigurationProvider): IDisposable;
unregisterDebugConfigurationProvider(debugConfigurationProvider: IDebugConfigurationProvider): void;
Expand Down

0 comments on commit b1a66b5

Please sign in to comment.