提交 dba0076c 编写于 作者: A Andre Weinand

add API resolveDebugConfigurationWithSubstitutedVariables; see #85206

上级 5c9a0af4
...@@ -788,7 +788,25 @@ declare module 'vscode' { ...@@ -788,7 +788,25 @@ declare module 'vscode' {
//#endregion //#endregion
//#region Debug //#region Debug:
export interface DebugConfigurationProvider {
/**
* This hook is directly called after 'resolveDebugConfiguration' but with all variables substituted.
* It can be used to resolve or verify a [debug configuration](#DebugConfiguration) by filling in missing values or by adding/changing/removing attributes.
* If more than one debug configuration provider is registered for the same type, the 'resolveDebugConfigurationWithSubstitutedVariables' calls are chained
* in arbitrary order and the initial debug configuration is piped through the chain.
* Returning the value 'undefined' prevents the debug session from starting.
* Returning the value 'null' prevents the debug session from starting and opens the underlying debug configuration instead.
*
* @param folder The workspace folder from which the configuration originates from or `undefined` for a folderless setup.
* @param debugConfiguration The [debug configuration](#DebugConfiguration) to resolve.
* @param token A cancellation token.
* @return The resolved debug configuration or undefined or null.
*/
resolveDebugConfigurationWithSubstitutedVariables?(folder: WorkspaceFolder | undefined, debugConfiguration: DebugConfiguration, token?: CancellationToken): ProviderResult<DebugConfiguration>;
}
// deprecated // deprecated
......
...@@ -154,7 +154,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb ...@@ -154,7 +154,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
return Promise.resolve(); return Promise.resolve();
} }
public $registerDebugConfigurationProvider(debugType: string, hasProvide: boolean, hasResolve: boolean, hasProvideDebugAdapter: boolean, handle: number): Promise<void> { public $registerDebugConfigurationProvider(debugType: string, hasProvide: boolean, hasResolve: boolean, hasResolve2: boolean, hasProvideDebugAdapter: boolean, handle: number): Promise<void> {
const provider = <IDebugConfigurationProvider>{ const provider = <IDebugConfigurationProvider>{
type: debugType type: debugType
...@@ -169,6 +169,11 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb ...@@ -169,6 +169,11 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
return this._proxy.$resolveDebugConfiguration(handle, folder, config, token); return this._proxy.$resolveDebugConfiguration(handle, folder, config, token);
}; };
} }
if (hasResolve2) {
provider.resolveDebugConfigurationWithSubstitutedVariables = (folder, config, token) => {
return this._proxy.$resolveDebugConfigurationWithSubstitutedVariables(handle, folder, config, token);
};
}
if (hasProvideDebugAdapter) { if (hasProvideDebugAdapter) {
console.info('DebugConfigurationProvider.debugAdapterExecutable is deprecated and will be removed soon; please use DebugAdapterDescriptorFactory.createDebugAdapterDescriptor instead.'); console.info('DebugConfigurationProvider.debugAdapterExecutable is deprecated and will be removed soon; please use DebugAdapterDescriptorFactory.createDebugAdapterDescriptor instead.');
provider.debugAdapterExecutable = (folder) => { provider.debugAdapterExecutable = (folder) => {
......
...@@ -750,7 +750,7 @@ export interface MainThreadDebugServiceShape extends IDisposable { ...@@ -750,7 +750,7 @@ export interface MainThreadDebugServiceShape extends IDisposable {
$acceptDAMessage(handle: number, message: DebugProtocol.ProtocolMessage): void; $acceptDAMessage(handle: number, message: DebugProtocol.ProtocolMessage): void;
$acceptDAError(handle: number, name: string, message: string, stack: string | undefined): void; $acceptDAError(handle: number, name: string, message: string, stack: string | undefined): void;
$acceptDAExit(handle: number, code: number | undefined, signal: string | undefined): void; $acceptDAExit(handle: number, code: number | undefined, signal: string | undefined): void;
$registerDebugConfigurationProvider(type: string, hasProvideMethod: boolean, hasResolveMethod: boolean, hasProvideDaMethod: boolean, handle: number): Promise<void>; $registerDebugConfigurationProvider(type: string, hasProvideMethod: boolean, hasResolveMethod: boolean, hasResolve2Method: boolean, hasProvideDaMethod: boolean, handle: number): Promise<void>;
$registerDebugAdapterDescriptorFactory(type: string, handle: number): Promise<void>; $registerDebugAdapterDescriptorFactory(type: string, handle: number): Promise<void>;
$unregisterDebugConfigurationProvider(handle: number): void; $unregisterDebugConfigurationProvider(handle: number): void;
$unregisterDebugAdapterDescriptorFactory(handle: number): void; $unregisterDebugAdapterDescriptorFactory(handle: number): void;
...@@ -1337,6 +1337,7 @@ export interface ExtHostDebugServiceShape { ...@@ -1337,6 +1337,7 @@ export interface ExtHostDebugServiceShape {
$stopDASession(handle: number): Promise<void>; $stopDASession(handle: number): Promise<void>;
$sendDAMessage(handle: number, message: DebugProtocol.ProtocolMessage): void; $sendDAMessage(handle: number, message: DebugProtocol.ProtocolMessage): void;
$resolveDebugConfiguration(handle: number, folder: UriComponents | undefined, debugConfiguration: IConfig, token: CancellationToken): Promise<IConfig | null | undefined>; $resolveDebugConfiguration(handle: number, folder: UriComponents | undefined, debugConfiguration: IConfig, token: CancellationToken): Promise<IConfig | null | undefined>;
$resolveDebugConfigurationWithSubstitutedVariables(handle: number, folder: UriComponents | undefined, debugConfiguration: IConfig, token: CancellationToken): Promise<IConfig | null | undefined>;
$provideDebugConfigurations(handle: number, folder: UriComponents | undefined, token: CancellationToken): Promise<IConfig[]>; $provideDebugConfigurations(handle: number, folder: UriComponents | undefined, token: CancellationToken): Promise<IConfig[]>;
$legacyDebugAdapterExecutable(handle: number, folderUri: UriComponents | undefined): Promise<IAdapterDescriptor>; // TODO@AW legacy $legacyDebugAdapterExecutable(handle: number, folderUri: UriComponents | undefined): Promise<IAdapterDescriptor>; // TODO@AW legacy
$provideDebugAdapter(handle: number, session: IDebugSessionDto): Promise<IAdapterDescriptor>; $provideDebugAdapter(handle: number, session: IDebugSessionDto): Promise<IAdapterDescriptor>;
......
...@@ -315,6 +315,7 @@ export class ExtHostDebugServiceBase implements IExtHostDebugService, ExtHostDeb ...@@ -315,6 +315,7 @@ export class ExtHostDebugServiceBase implements IExtHostDebugService, ExtHostDeb
this._debugServiceProxy.$registerDebugConfigurationProvider(type, this._debugServiceProxy.$registerDebugConfigurationProvider(type,
!!provider.provideDebugConfigurations, !!provider.provideDebugConfigurations,
!!provider.resolveDebugConfiguration, !!provider.resolveDebugConfiguration,
!!provider.resolveDebugConfigurationWithSubstitutedVariables,
!!provider.debugAdapterExecutable, // TODO@AW: deprecated !!provider.debugAdapterExecutable, // TODO@AW: deprecated
handle); handle);
...@@ -628,6 +629,20 @@ export class ExtHostDebugServiceBase implements IExtHostDebugService, ExtHostDeb ...@@ -628,6 +629,20 @@ export class ExtHostDebugServiceBase implements IExtHostDebugService, ExtHostDeb
}); });
} }
public $resolveDebugConfigurationWithSubstitutedVariables(configProviderHandle: number, folderUri: UriComponents | undefined, debugConfiguration: vscode.DebugConfiguration, token: CancellationToken): Promise<vscode.DebugConfiguration | null | undefined> {
return asPromise(async () => {
const provider = this.getConfigProviderByHandle(configProviderHandle);
if (!provider) {
throw new Error('no DebugConfigurationProvider found');
}
if (!provider.resolveDebugConfigurationWithSubstitutedVariables) {
throw new Error('DebugConfigurationProvider has no method resolveDebugConfigurationWithSubstitutedVariables');
}
const folder = await this.getFolder(folderUri);
return provider.resolveDebugConfigurationWithSubstitutedVariables(folder, debugConfiguration, token);
});
}
// TODO@AW deprecated and legacy // TODO@AW deprecated and legacy
public $legacyDebugAdapterExecutable(configProviderHandle: number, folderUri: UriComponents | undefined): Promise<IAdapterDescriptor> { public $legacyDebugAdapterExecutable(configProviderHandle: number, folderUri: UriComponents | undefined): Promise<IAdapterDescriptor> {
return asPromise(async () => { return asPromise(async () => {
......
...@@ -207,6 +207,22 @@ export class ConfigurationManager implements IConfigurationManager { ...@@ -207,6 +207,22 @@ export class ConfigurationManager implements IConfigurationManager {
return result; return result;
} }
async resolveDebugConfigurationWithSubstitutedVariables(folderUri: uri | undefined, type: string | undefined, config: IConfig, token: CancellationToken): Promise<IConfig | null | undefined> {
// pipe the config through the promises sequentially. Append at the end the '*' types
const providers = this.configProviders.filter(p => p.type === type && p.resolveDebugConfigurationWithSubstitutedVariables)
.concat(this.configProviders.filter(p => p.type === '*' && p.resolveDebugConfigurationWithSubstitutedVariables));
let result: IConfig | null | undefined = config;
await sequence(providers.map(provider => async () => {
// If any provider returned undefined or null make sure to respect that and do not pass the result to more resolver
if (result) {
result = await provider.resolveDebugConfigurationWithSubstitutedVariables!(folderUri, result, token);
}
}));
return result;
}
async provideDebugConfigurations(folderUri: uri | undefined, type: string, token: CancellationToken): Promise<any[]> { async provideDebugConfigurations(folderUri: uri | undefined, type: string, token: CancellationToken): Promise<any[]> {
await this.activateDebuggers('onDebugInitialConfigurations'); await this.activateDebuggers('onDebugInitialConfigurations');
const results = await Promise.all(this.configProviders.filter(p => p.type === type && p.provideDebugConfigurations).map(p => p.provideDebugConfigurations!(folderUri, token))); const results = await Promise.all(this.configProviders.filter(p => p.type === type && p.provideDebugConfigurations).map(p => p.provideDebugConfigurations!(folderUri, token)));
......
...@@ -379,13 +379,22 @@ export class DebugService implements IDebugService { ...@@ -379,13 +379,22 @@ export class DebugService implements IDebugService {
// a falsy config indicates an aborted launch // a falsy config indicates an aborted launch
if (configByProviders && configByProviders.type) { if (configByProviders && configByProviders.type) {
try { try {
const resolvedConfig = await this.substituteVariables(launch, configByProviders); let resolvedConfig = await this.substituteVariables(launch, configByProviders);
if (!resolvedConfig) { if (!resolvedConfig) {
// User canceled resolving of interactive variables, silently return // User canceled resolving of interactive variables, silently return
return false; return false;
} }
const cfg = await this.configurationManager.resolveDebugConfigurationWithSubstitutedVariables(launch && launch.workspace ? launch.workspace.uri : undefined, type, resolvedConfig, this.initCancellationToken.token);
if (!cfg) {
if (launch && type && cfg === null) { // show launch.json only for "config" being "null".
await launch.openConfigFile(false, true, type, this.initCancellationToken ? this.initCancellationToken.token : undefined);
}
return false;
}
resolvedConfig = cfg;
if (!this.configurationManager.getDebugger(resolvedConfig.type) || (configByProviders.request !== 'attach' && configByProviders.request !== 'launch')) { if (!this.configurationManager.getDebugger(resolvedConfig.type) || (configByProviders.request !== 'attach' && configByProviders.request !== 'launch')) {
let message: string; let message: string;
if (configByProviders.request !== 'attach' && configByProviders.request !== 'launch') { if (configByProviders.request !== 'attach' && configByProviders.request !== 'launch') {
...@@ -639,6 +648,9 @@ export class DebugService implements IDebugService { ...@@ -639,6 +648,9 @@ export class DebugService implements IDebugService {
const resolvedByProviders = await this.configurationManager.resolveConfigurationByProviders(launch.workspace ? launch.workspace.uri : undefined, unresolved.type, unresolved, this.initCancellationToken.token); const resolvedByProviders = await this.configurationManager.resolveConfigurationByProviders(launch.workspace ? launch.workspace.uri : undefined, unresolved.type, unresolved, this.initCancellationToken.token);
if (resolvedByProviders) { if (resolvedByProviders) {
resolved = await this.substituteVariables(launch, resolvedByProviders); resolved = await this.substituteVariables(launch, resolvedByProviders);
if (resolved) {
resolved = await this.configurationManager.resolveDebugConfigurationWithSubstitutedVariables(launch && launch.workspace ? launch.workspace.uri : undefined, unresolved.type, resolved, this.initCancellationToken.token);
}
} else { } else {
resolved = resolvedByProviders; resolved = resolvedByProviders;
} }
......
...@@ -599,6 +599,7 @@ export interface IDebuggerContribution extends IPlatformSpecificAdapterContribut ...@@ -599,6 +599,7 @@ export interface IDebuggerContribution extends IPlatformSpecificAdapterContribut
export interface IDebugConfigurationProvider { export interface IDebugConfigurationProvider {
readonly type: string; readonly type: string;
resolveDebugConfiguration?(folderUri: uri | undefined, debugConfiguration: IConfig, token: CancellationToken): Promise<IConfig | null | undefined>; resolveDebugConfiguration?(folderUri: uri | undefined, debugConfiguration: IConfig, token: CancellationToken): Promise<IConfig | null | undefined>;
resolveDebugConfigurationWithSubstitutedVariables?(folderUri: uri | undefined, debugConfiguration: IConfig, token: CancellationToken): Promise<IConfig | null | undefined>;
provideDebugConfigurations?(folderUri: uri | undefined, token: CancellationToken): Promise<IConfig[]>; provideDebugConfigurations?(folderUri: uri | undefined, token: CancellationToken): Promise<IConfig[]>;
debugAdapterExecutable?(folderUri: uri | undefined): Promise<IAdapterDescriptor>; // TODO@AW legacy debugAdapterExecutable?(folderUri: uri | undefined): Promise<IAdapterDescriptor>; // TODO@AW legacy
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册