Skip to content

Commit

Permalink
Associate root folder to dynamic debug configurations
Browse files Browse the repository at this point in the history
The methods is the `vscode` interface `DebugConfigurationProvider`
specify the parameter `folder: WorksapceFolder | undefined'.

The parameter can be `undefined` in the context of a folderless setup
however some plugins expect it to be present always
(e.g. ms-python.python). The original implementation of dynamic debug
configurations did not provide this parameter.

This change associates the root folder to the contributed
configurations directly after the response for the call to
'provideDebugConfigurations' and it makes sure to preserve this
parameter within the pick items presented to the user.

Signed-off-by: Alvaro Sanchez-Leon <alvaro.sanchez-leon@ericsson.com>
  • Loading branch information
alvsan09 committed May 12, 2023
1 parent 9525159 commit aad3b80
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 35 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
- [Previous Changelogs](https://github.com/eclipse-theia/theia/tree/master/doc/changelogs/)


## v1.38.0 - 04/27/2023
## v1.38.0 - 05/25/2023

<a name="breaking_changes_1.38.0">[Breaking Changes:](#breaking_changes_1.38.0)</a>

- [core] moved `ToolbarAwareTabBar.Styles` to `ScrollableTabBar.Styles` [12411](https://github.com/eclipse-theia/theia/pull/12411/)
- [debug] Change the return type of (method) `DebugConfigurationManager.provideDynamicDebugConfigurations()` to <br>
`Promise<Record<string, DynamicDebugConfigurationSessionOptions[]>>` [#12482](https://github.com/eclipse-theia/theia/pull/12482)

## v1.37.0 - 04/27/2023

Expand Down
43 changes: 35 additions & 8 deletions packages/debug/src/browser/debug-configuration-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,8 @@ export class DebugConfigurationManager {

// Refresh a dynamic configuration from the provider.
// This allow providers to update properties before the execution e.g. program
const { providerType, configuration: { name } } = this._currentOptions;
const configuration = await this.fetchDynamicDebugConfiguration(name, providerType);
const { providerType, workspaceFolderUri, configuration: { name } } = this._currentOptions;
const configuration = await this.fetchDynamicDebugConfiguration(name, providerType, workspaceFolderUri);

if (!configuration) {
const message = nls.localize(
Expand All @@ -188,7 +188,7 @@ export class DebugConfigurationManager {
throw new Error(message);
}

return { name, configuration, providerType };
return { name, configuration, providerType, workspaceFolderUri };
}

set current(option: DebugSessionOptions | undefined) {
Expand All @@ -215,7 +215,8 @@ export class DebugConfigurationManager {
protected dynamicOptionsMatch(one: DynamicDebugConfigurationSessionOptions, other: DynamicDebugConfigurationSessionOptions): boolean {
return one.providerType !== undefined
&& one.configuration.name === other.configuration.name
&& one.providerType === other.providerType;
&& one.providerType === other.providerType
&& one.workspaceFolderUri === other.workspaceFolderUri;
}

get recentDynamicOptions(): readonly DynamicDebugConfigurationSessionOptions[] {
Expand Down Expand Up @@ -462,14 +463,40 @@ export class DebugConfigurationManager {
await WaitUntilEvent.fire(this.onWillProvideDebugConfigurationEmitter, {});
}

async provideDynamicDebugConfigurations(): Promise<Record<string, DebugConfiguration[]>> {
async provideDynamicDebugConfigurations(): Promise<Record<string, DynamicDebugConfigurationSessionOptions[]>> {
await this.fireWillProvideDynamicDebugConfiguration();
return this.debug.provideDynamicDebugConfigurations!();
const roots = this.workspaceService.tryGetRoots();
const promises = roots.map(async root => {
const configsMap = await this.debug.provideDynamicDebugConfigurations!(root.resource.toString());
const optionsMap = Object.fromEntries(Object.entries(configsMap).map(([type, configs]) => {
const options = configs.map(config => ({
name: config.name,
providerType: type,
configuration: config,
workspaceFolderUri: root.resource.toString()
}));
return [type, options];
}));
return optionsMap;
});

const typesToOptionsRecords = await Promise.all(promises);
const consolidatedTypesToOptions: Record<string, DynamicDebugConfigurationSessionOptions[]> = {};

for (const typesToOptionsInstance of typesToOptionsRecords) {
for (const [providerType, configurationsOptions] of Object.entries(typesToOptionsInstance)) {
if (!consolidatedTypesToOptions[providerType]) {
consolidatedTypesToOptions[providerType] = [];
}
consolidatedTypesToOptions[providerType].push(...configurationsOptions);
}
}
return consolidatedTypesToOptions;
}

async fetchDynamicDebugConfiguration(name: string, type: string): Promise<DebugConfiguration | undefined> {
async fetchDynamicDebugConfiguration(name: string, type: string, folder?: string): Promise<DebugConfiguration | undefined> {
await this.fireWillProvideDynamicDebugConfiguration();
return this.debug.fetchDynamicDebugConfiguration(name, type);
return this.debug.fetchDynamicDebugConfiguration(name, type, folder);
}

protected async fireWillProvideDynamicDebugConfiguration(): Promise<void> {
Expand Down
21 changes: 13 additions & 8 deletions packages/debug/src/browser/debug-prefix-configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,34 +107,39 @@ export class DebugPrefixConfiguration implements CommandContribution, CommandHan
});
}

protected resolveRootFolderName(uri: string | undefined): string | undefined {
return uri && this.workspaceService.isMultiRootWorkspaceOpened
? this.labelProvider.getName(new URI(uri))
: '';
}

async getPicks(filter: string, token: CancellationToken): Promise<QuickPicks> {
const items: QuickPickItemOrSeparator[] = [];
const configurations = this.debugConfigurationManager.all;

for (const config of configurations) {
items.push({
label: config.name,
description: this.workspaceService.isMultiRootWorkspaceOpened
? this.labelProvider.getName(new URI(config.workspaceFolderUri))
: '',
description: this.resolveRootFolderName(config.workspaceFolderUri),
execute: () => this.runConfiguration(config)
});
}

// Resolve dynamic configurations from providers
const record = await this.debugConfigurationManager.provideDynamicDebugConfigurations();
for (const [providerType, dynamicConfigurations] of Object.entries(record)) {
if (dynamicConfigurations.length > 0) {
for (const [providerType, configurationOptions] of Object.entries(record)) {
if (configurationOptions.length > 0) {
items.push({
label: providerType,
type: 'separator'
});
}

for (const configuration of dynamicConfigurations) {
for (const options of configurationOptions) {
items.push({
label: configuration.name,
execute: () => this.runConfiguration({ name: configuration.name, configuration, providerType })
label: options.name,
description: this.resolveRootFolderName(options.workspaceFolderUri),
execute: () => this.runConfiguration({ name: options.name, configuration: options.configuration, providerType, workspaceFolderUri: options.workspaceFolderUri })
});
}
}
Expand Down
28 changes: 17 additions & 11 deletions packages/debug/src/browser/view/debug-configuration-select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { SelectComponent, SelectOption } from '@theia/core/lib/browser/widgets/s
import { QuickInputService } from '@theia/core/lib/browser';
import { nls } from '@theia/core/lib/common/nls';

interface DynamicPickItem { label: string, configurationType: string, request: string, providerType: string }
interface DynamicPickItem { label: string, configurationType: string, request: string, providerType: string, workspaceFolderUri?: string }

export interface DebugConfigurationSelectProps {
manager: DebugConfigurationManager,
Expand Down Expand Up @@ -130,11 +130,13 @@ export class DebugConfigurationSelect extends React.Component<DebugConfiguration
return [];
}

return configurationsOfProviderType.map(configuration => ({
label: configuration.name,
configurationType: configuration.type,
request: configuration.request,
providerType
return configurationsOfProviderType.map(options => ({
label: options.configuration.name,
configurationType: options.configuration.type,
request: options.configuration.request,
providerType: options.providerType,
description: this.toBaseName(options.workspaceFolderUri),
workspaceFolderUri: options.workspaceFolderUri
}));
}

Expand All @@ -161,15 +163,15 @@ export class DebugConfigurationSelect extends React.Component<DebugConfiguration
type: selected.configurationType,
request: selected.request
};
this.manager.current = this.manager.find(selectedConfiguration, undefined, selected.providerType);
this.manager.current = this.manager.find(selectedConfiguration, selected.workspaceFolderUri, selected.providerType);
this.refreshDebugConfigurations();
}

protected refreshDebugConfigurations = async () => {
const configsPerType = await this.manager.provideDynamicDebugConfigurations();
const configsOptionsPerType = await this.manager.provideDynamicDebugConfigurations();
const providerTypes = [];
for (const [type, configurations] of Object.entries(configsPerType)) {
if (configurations.length > 0) {
for (const [type, configurationsOptions] of Object.entries(configsOptionsPerType)) {
if (configurationsOptions.length > 0) {
providerTypes.push(type);
}
}
Expand Down Expand Up @@ -251,6 +253,10 @@ export class DebugConfigurationSelect extends React.Component<DebugConfiguration
if (!options.workspaceFolderUri || !multiRoot) {
return name;
}
return `${name} (${new URI(options.workspaceFolderUri).path.base})`;
return `${name} (${this.toBaseName(options.workspaceFolderUri)})`;
}

protected toBaseName(uri: string | undefined): string {
return uri ? new URI(uri).path.base : '';
}
}
4 changes: 2 additions & 2 deletions packages/debug/src/common/debug-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,12 @@ export interface DebugService extends Disposable {
/**
* @returns A Record of debug configuration provider types and a corresponding dynamic debug configurations array
*/
provideDynamicDebugConfigurations?(): Promise<Record<string, DebugConfiguration[]>>;
provideDynamicDebugConfigurations?(folder?: string): Promise<Record<string, DebugConfiguration[]>>;

/**
* Provides a dynamic debug configuration matching the name and the provider debug type
*/
fetchDynamicDebugConfiguration(name: string, type: string): Promise<DebugConfiguration | undefined>;
fetchDynamicDebugConfiguration(name: string, type: string, folder?: string): Promise<DebugConfiguration | undefined>;

/**
* Resolves a [debug configuration](#DebugConfiguration) by filling in missing values
Expand Down
2 changes: 1 addition & 1 deletion packages/debug/src/node/debug-service-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export class DebugServiceImpl implements DebugService {
// TODO: Support dynamic debug configurations through Theia extensions?
return {};
}
fetchDynamicDebugConfiguration(name: string, type: string): Promise<DebugConfiguration | undefined> {
fetchDynamicDebugConfiguration(name: string, type: string, folder?: string): Promise<DebugConfiguration | undefined> {
// TODO: Support dynamic debug configurations through Theia extensions?
return Promise.resolve(undefined);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export class PluginDebugService implements DebugService {
return results;
}

async fetchDynamicDebugConfiguration(name: string, providerType: string): Promise<DebugConfiguration | undefined> {
async fetchDynamicDebugConfiguration(name: string, providerType: string, folder?: string): Promise<DebugConfiguration | undefined> {
const pluginProviders =
Array.from(this.configurationProviders.values()).filter(p => (
p.triggerKind === DebugConfigurationProviderTriggerKind.Dynamic &&
Expand All @@ -151,7 +151,7 @@ export class PluginDebugService implements DebugService {
));

for (const provider of pluginProviders) {
const configurations = await provider.provideDebugConfigurations(undefined);
const configurations = await provider.provideDebugConfigurations(folder);
for (const configuration of configurations) {
if (configuration.name === name) {
return configuration;
Expand All @@ -160,7 +160,7 @@ export class PluginDebugService implements DebugService {
}
}

async provideDynamicDebugConfigurations(): Promise<Record<string, DebugConfiguration[]>> {
async provideDynamicDebugConfigurations(folder?: string): Promise<Record<string, DebugConfiguration[]>> {
const pluginProviders =
Array.from(this.configurationProviders.values()).filter(p => (
p.triggerKind === DebugConfigurationProviderTriggerKind.Dynamic &&
Expand All @@ -170,7 +170,7 @@ export class PluginDebugService implements DebugService {
const configurationsRecord: Record<string, DebugConfiguration[]> = {};

await Promise.all(pluginProviders.map(async provider => {
const configurations = await provider.provideDebugConfigurations(undefined);
const configurations = await provider.provideDebugConfigurations(folder);
let configurationsPerType = configurationsRecord[provider.type];
configurationsPerType = configurationsPerType ? configurationsPerType.concat(configurations) : configurations;

Expand Down

0 comments on commit aad3b80

Please sign in to comment.