Skip to content

Commit

Permalink
Separate debug configuration providers from debug adapter contributors
Browse files Browse the repository at this point in the history
The implementation of the vscode API for the resolution of initial
debug configurations as well as the resolution of specific
configurations was relying on the registered debug adapter
contributors rather than debug configuration providers,
this is causing issues e.g. #9978.

This implementation brings access to the debug configuration
providers all the way to the browser debug/plugin-debug-service,
where the providers can be filtered and then call its corresponding
API indirectly.

The former API is kept as deprecated.

Signed-off-by: Alvaro Sanchez-Leon <[email protected]>
  • Loading branch information
alvsan09 committed Mar 24, 2022
1 parent acd6f57 commit 219827d
Show file tree
Hide file tree
Showing 11 changed files with 353 additions and 139 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@ dev-packages/electron/compile_commands.json
scripts/download
license-check-summary.txt*
*-trace.json
.tours
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@
- `commandService`, `instantiationService` removed from `MonacoEditor`. Use `StandaloneServices.get(IInstantationService / ICommandService)` instead.
- `DecorationMiniMapOptions.position`, `DecorationOverviewRulerOptions.position` no longer optional.
- Overrides used by `MonacoEditorFactory` accept the type `EditorServiceOverrides` rather than `{[key: string]: any}`.
- [debug] The interface method `DebugService#provideDynamicDebugConfigurations` changes the return type to `Map<string, DebugConfiguration[]>`.
This impacts the corresponding return type for `DebugConfigurationManager#provideDynamicDebugConfigurations`.
The following functions under `plugin-api-rpc.ts#DebugExt` and in the `PluginDebugAdapterContribution` are deprecated
* $provideDebugConfigurations
* $resolveDebugConfigurations
* $resolveDebugConfigurationWithSubstitutedVariablesByHandle

The `PluginDebugAdapterContributionRegistrator` interface has been removed


## v1.23.0 - 2/24/2022

Expand Down
2 changes: 1 addition & 1 deletion packages/debug/src/browser/debug-configuration-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ export class DebugConfigurationManager {
await WaitUntilEvent.fire(this.onWillProvideDebugConfigurationEmitter, {});
}

async provideDynamicDebugConfigurations(): Promise<{ type: string, configurations: DebugConfiguration[] }[]> {
async provideDynamicDebugConfigurations(): Promise<Map<string, DebugConfiguration[]>> {
await this.fireWillProvideDynamicDebugConfiguration();
return this.debug.provideDynamicDebugConfigurations!();
}
Expand Down
7 changes: 3 additions & 4 deletions packages/debug/src/browser/debug-prefix-configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,11 @@ export class DebugPrefixConfiguration implements CommandContribution, CommandHan
}

// Resolve dynamic configurations from providers
const configurationsByType = await this.debugConfigurationManager.provideDynamicDebugConfigurations();
for (const typeConfigurations of configurationsByType) {
const dynamicConfigurations = typeConfigurations.configurations;
const map = await this.debugConfigurationManager.provideDynamicDebugConfigurations();
for (const [type, dynamicConfigurations] of map) {
if (dynamicConfigurations.length > 0) {
items.push({
label: typeConfigurations.type,
label: type,
type: 'separator'
});
}
Expand Down
28 changes: 25 additions & 3 deletions packages/debug/src/common/debug-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,29 @@ export interface DebuggerDescription {
label: string
}

export enum DebugConfigurationProviderTriggerKind {
Initial = 1,
Dynamic = 2
}

export interface DebugConfigurationProvider {
readonly handle: number;
readonly type: string;
readonly triggerKind: DebugConfigurationProviderTriggerKind;
provideDebugConfigurations?(folder: string | undefined): Promise<DebugConfiguration[]>;
resolveDebugConfiguration?(folder: string | undefined, debugConfiguration: DebugConfiguration): Promise<DebugConfiguration | undefined>;
resolveDebugConfigurationWithSubstitutedVariables?(folder: string | undefined, debugConfiguration: DebugConfiguration): Promise<DebugConfiguration | undefined>;
}

export interface DebugConfigurationProviderDescriptor {
readonly handle: number,
readonly type: string,
readonly trigger: DebugConfigurationProviderTriggerKind,
readonly provideDebugConfiguration: boolean,
readonly resolveDebugConfigurations: boolean,
readonly resolveDebugConfigurationWithSubstitutedVariables: boolean
}

/**
* The WS endpoint path to the Debug service.
*/
Expand Down Expand Up @@ -71,10 +94,9 @@ export interface DebugService extends Disposable {
provideDebugConfigurations(debugType: string, workspaceFolderUri: string | undefined): Promise<DebugConfiguration[]>;

/**
* Provides dynamic debug configurations by a provider debug type
* @returns An Array of objects containing the debug type and corresponding dynamic debug configurations array
* @returns A map of debug configuration provider types and a corresponding dynamic debug configurations array
*/
provideDynamicDebugConfigurations?(): Promise<{ type: string, configurations: DebugConfiguration[] }[]>;
provideDynamicDebugConfigurations?(): Promise<Map<string, DebugConfiguration[]>>;

/**
* Resolves a [debug configuration](#DebugConfiguration) by filling in missing values
Expand Down
27 changes: 27 additions & 0 deletions packages/plugin-ext/src/common/plugin-api-rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1649,16 +1649,41 @@ export enum DebugConfigurationProviderTriggerKind {
Dynamic = 2
}

export interface DebugConfigurationProviderDescriptor {
readonly handle: number,
readonly type: string,
readonly trigger: DebugConfigurationProviderTriggerKind,
readonly provideDebugConfiguration: boolean,
readonly resolveDebugConfigurations: boolean,
readonly resolveDebugConfigurationWithSubstitutedVariables: boolean
}

export interface DebugExt {
$onSessionCustomEvent(sessionId: string, event: string, body?: any): void;
$breakpointsDidChange(added: Breakpoint[], removed: string[], changed: Breakpoint[]): void;
$sessionDidCreate(sessionId: string): void;
$sessionDidDestroy(sessionId: string): void;
$sessionDidChange(sessionId: string | undefined): void;
/**
* @deprecated since 1.24.0. Use $registerDebugConfigurationProvider with $provideDebugConfigurationsByHandle instead.
*/
$provideDebugConfigurations(debugType: string, workspaceFolder: string | undefined, dynamic?: boolean): Promise<theia.DebugConfiguration[]>;

/**
* @deprecated since 1.24.0. Use $registerDebugConfigurationProvider with $resolveDebugConfigurationByHandle instead.
*/
$resolveDebugConfigurations(debugConfiguration: theia.DebugConfiguration, workspaceFolder: string | undefined): Promise<theia.DebugConfiguration | undefined>;

/**
* @deprecated since 1.24.0. Use $registerDebugConfigurationProvider with $resolveDebugConfigurationWithSubstitutedVariablesByHandle instead.
*/
$resolveDebugConfigurationWithSubstitutedVariables(debugConfiguration: theia.DebugConfiguration, workspaceFolder: string | undefined):
Promise<theia.DebugConfiguration | undefined>;

$provideDebugConfigurationsByHandle(handle: number, workspaceFolder: string | undefined): Promise<theia.DebugConfiguration[]>;
$resolveDebugConfigurationByHandle(handle: number, workspaceFolder: string | undefined, debugConfiguration: theia.DebugConfiguration): Promise<theia.DebugConfiguration | undefined>;
$resolveDebugConfigurationWithSubstitutedVariablesByHandle(handle: number, workspaceFolder: string | undefined, debugConfiguration: theia.DebugConfiguration): Promise<theia.DebugConfiguration | undefined>;

$createDebugSession(debugConfiguration: theia.DebugConfiguration): Promise<string>;
$terminateDebugSession(sessionId: string): Promise<void>;
$getTerminalCreationOptions(debugType: string): Promise<TerminalOptionsExt | undefined>;
Expand All @@ -1669,6 +1694,8 @@ export interface DebugMain {
$appendLineToDebugConsole(value: string): Promise<void>;
$registerDebuggerContribution(description: DebuggerDescription): Promise<void>;
$unregisterDebuggerConfiguration(debugType: string): Promise<void>;
$registerDebugConfigurationProvider(description: DebugConfigurationProviderDescriptor): void;
$unregisterDebugConfigurationProvider(handle: number): Promise<void>;
$addBreakpoints(breakpoints: Breakpoint[]): Promise<void>;
$removeBreakpoints(breakpoints: string[]): Promise<void>;
$startDebugging(folder: theia.WorkspaceFolder | undefined, nameOrConfiguration: string | theia.DebugConfiguration, options: theia.DebugSessionOptions): Promise<boolean>;
Expand Down
32 changes: 28 additions & 4 deletions packages/plugin-ext/src/main/browser/debug/debug-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import { interfaces } from '@theia/core/shared/inversify';
import { RPCProtocol } from '../../../common/rpc-protocol';
import {
DebugConfigurationProviderDescriptor,
DebugMain,
DebugExt,
MAIN_RPC_CONTEXT
Expand All @@ -40,10 +41,11 @@ import { MessageClient } from '@theia/core/lib/common/message-service-protocol';
import { OutputChannelManager } from '@theia/output/lib/browser/output-channel';
import { DebugPreferences } from '@theia/debug/lib/browser/debug-preferences';
import { PluginDebugAdapterContribution } from './plugin-debug-adapter-contribution';
import { PluginDebugConfigurationProvider } from './plugin-debug-configuration-provider';
import { PluginDebugSessionContributionRegistrator, PluginDebugSessionContributionRegistry } from './plugin-debug-session-contribution-registry';
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
import { PluginDebugSessionFactory } from './plugin-debug-session-factory';
import { PluginDebugAdapterContributionRegistrator, PluginDebugService } from './plugin-debug-service';
import { PluginDebugService } from './plugin-debug-service';
import { HostedPluginSupport } from '../../../hosted/browser/hosted-plugin';
import { DebugFunctionBreakpoint } from '@theia/debug/lib/browser/model/debug-function-breakpoint';
import { FileService } from '@theia/filesystem/lib/browser/file-service';
Expand All @@ -67,12 +69,13 @@ export class DebugMainImpl implements DebugMain, Disposable {
private readonly outputChannelManager: OutputChannelManager;
private readonly debugPreferences: DebugPreferences;
private readonly sessionContributionRegistrator: PluginDebugSessionContributionRegistrator;
private readonly adapterContributionRegistrator: PluginDebugAdapterContributionRegistrator;
private readonly pluginDebugService: PluginDebugService;
private readonly fileService: FileService;
private readonly pluginService: HostedPluginSupport;
private readonly debugContributionProvider: ContributionProvider<DebugContribution>;

private readonly debuggerContributions = new Map<string, DisposableCollection>();
private readonly configurationProviders = new Map<number, DisposableCollection>();
private readonly toDispose = new DisposableCollection();

constructor(rpc: RPCProtocol, readonly connectionMain: ConnectionImpl, container: interfaces.Container) {
Expand All @@ -87,7 +90,7 @@ export class DebugMainImpl implements DebugMain, Disposable {
this.messages = container.get(MessageClient);
this.outputChannelManager = container.get(OutputChannelManager);
this.debugPreferences = container.get(DebugPreferences);
this.adapterContributionRegistrator = container.get(PluginDebugService);
this.pluginDebugService = container.get(PluginDebugService);
this.sessionContributionRegistrator = container.get(PluginDebugSessionContributionRegistry);
this.debugContributionProvider = container.getNamed(ContributionProvider, DebugContribution);
this.fileService = container.get(FileService);
Expand Down Expand Up @@ -160,7 +163,7 @@ export class DebugMainImpl implements DebugMain, Disposable {
);
this.debuggerContributions.set(debugType, toDispose);
toDispose.pushAll([
this.adapterContributionRegistrator.registerDebugAdapterContribution(
this.pluginDebugService.registerDebugAdapterContribution(
new PluginDebugAdapterContribution(description, this.debugExt, this.pluginService)
),
this.sessionContributionRegistrator.registerDebugSessionContribution({
Expand All @@ -178,6 +181,27 @@ export class DebugMainImpl implements DebugMain, Disposable {
}
}

$registerDebugConfigurationProvider(description: DebugConfigurationProviderDescriptor): void {
const handle = description.handle;
const toDispose = new DisposableCollection(
Disposable.create(() => this.configurationProviders.delete(handle))
);
this.configurationProviders.set(handle, toDispose);

toDispose.push(
this.pluginDebugService.registerDebugConfigurationProvider(new PluginDebugConfigurationProvider(description, this.debugExt))
);

this.toDispose.push(Disposable.create(() => this.$unregisterDebugConfigurationProvider(handle)));
}

async $unregisterDebugConfigurationProvider(handle: number): Promise<void> {
const disposable = this.configurationProviders.get(handle);
if (disposable) {
disposable.dispose();
}
}

async $addBreakpoints(breakpoints: Breakpoint[]): Promise<void> {
const newBreakpoints = new Map<string, Breakpoint>();
breakpoints.forEach(b => newBreakpoints.set(b.id, b));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,23 @@ export class PluginDebugAdapterContribution {
return this.description.label;
}

/**
* @deprecated since 1.24.0, Use [PluginDebugConfigurationProvider](plugin-debug-configuration-provider.ts)
*/
async provideDebugConfigurations(workspaceFolderUri: string | undefined, dynamic: boolean = false): Promise<DebugConfiguration[]> {
return this.debugExt.$provideDebugConfigurations(this.type, workspaceFolderUri, dynamic);
}

/**
* @deprecated since 1.24.0, Use [PluginDebugConfigurationProvider](plugin-debug-configuration-provider.ts)
*/
async resolveDebugConfiguration(config: DebugConfiguration, workspaceFolderUri: string | undefined): Promise<DebugConfiguration | undefined> {
return this.debugExt.$resolveDebugConfigurations(config, workspaceFolderUri);
}

/**
* @deprecated since 1.24.0, Use [PluginDebugConfigurationProvider](plugin-debug-configuration-provider.ts)
*/
async resolveDebugConfigurationWithSubstitutedVariables(config: DebugConfiguration, workspaceFolderUri: string | undefined): Promise<DebugConfiguration | undefined> {
return this.debugExt.$resolveDebugConfigurationWithSubstitutedVariables(config, workspaceFolderUri);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// *****************************************************************************
// Copyright (C) 2022 Ericsson and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
// *****************************************************************************

import { DebugExt } from '../../../common/plugin-api-rpc';
import { DebugConfiguration } from '@theia/debug/lib/common/debug-configuration';
import { DebugConfigurationProvider, DebugConfigurationProviderDescriptor, DebugConfigurationProviderTriggerKind } from '@theia/debug/lib/common/debug-service';

export class PluginDebugConfigurationProvider implements DebugConfigurationProvider {
private _handle: number;
private _type: string;
private trigger: DebugConfigurationProviderTriggerKind;
provideDebugConfigurations: (folder: string | undefined) => Promise<DebugConfiguration[]>;
resolveDebugConfiguration: (folder: string | undefined, debugConfiguration: DebugConfiguration) => Promise<DebugConfiguration | undefined>;
resolveDebugConfigurationWithSubstitutedVariables: (folder: string | undefined, debugConfiguration: DebugConfiguration) => Promise<DebugConfiguration | undefined>;

constructor(description: DebugConfigurationProviderDescriptor,
protected readonly debugExt: DebugExt) {
this._handle = description.handle;
this._type = description.type;
this.trigger = description.trigger;

if (description.provideDebugConfiguration) {
this.provideDebugConfigurations = async (folder: string | undefined) => this.debugExt.$provideDebugConfigurationsByHandle(this._handle, folder);
}

if (description.resolveDebugConfigurations) {
this.resolveDebugConfiguration =
async (folder: string | undefined, debugConfiguration: DebugConfiguration) =>
this.debugExt.$resolveDebugConfigurationByHandle(this._handle, folder, debugConfiguration);
}

if (description.resolveDebugConfigurationWithSubstitutedVariables) {
this.resolveDebugConfigurationWithSubstitutedVariables =
async (folder: string | undefined, debugConfiguration: DebugConfiguration) =>
this.debugExt.$resolveDebugConfigurationWithSubstitutedVariablesByHandle(this._handle, folder, debugConfiguration);
}
}

get handle(): number {
return this._handle;
}

get type(): string {
return this._type;
}

get triggerKind(): DebugConfigurationProviderTriggerKind {
return this.trigger;
}
}
Loading

0 comments on commit 219827d

Please sign in to comment.