Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Associate root folder to dynamic debug configurations #12482

Merged
merged 1 commit into from
May 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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