提交 81142e2c 编写于 作者: A Andre Weinand

support for debugAdapterExecutable; fixes #33801

上级 c0a5a09a
......@@ -359,6 +359,39 @@ declare module 'vscode' {
constructor(functionName: string, enabled?: boolean, condition?: string, hitCondition?: string);
}
/**
* Represents a debug adapter executable and optional arguments passed to it.
*/
export class DebugAdapterExecutable {
/**
* The command path of the debug adapter executable.
* A command must be a either an absolute path or a name of an executable looked up via the PATH environment variable.
* The special value 'node' will be mapped to VS Code's built-in node runtime.
*/
readonly command: string;
/**
* Optional arguments passed to the debug adapter.
*/
readonly args: string[];
/**
* Create a new debug adapter specification.
*/
constructor(command: string, args?: string[]);
}
export interface DebugConfigurationProvider {
/**
* This optional method is called just before a debug adapter is started to determine its excutable path and arguments.
* Registering more than one debugAdapterExecutable for a type results in an error.
* @param folder The workspace folder from which the configuration originates from or undefined for a folderless setup.
* @param token A cancellation token.
* @return a [debug adapter's executable and optional arguments](#DebugAdapterExecutable) or undefined.
*/
debugAdapterExecutable?(folder: WorkspaceFolder | undefined, token?: CancellationToken): ProviderResult<DebugAdapterExecutable>;
}
/**
* The severity level of a log message
*/
......
......@@ -148,7 +148,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape {
});
}
public $registerDebugConfigurationProvider(debugType: string, hasProvide: boolean, hasResolve: boolean, handle: number): TPromise<void> {
public $registerDebugConfigurationProvider(debugType: string, hasProvide: boolean, hasResolve: boolean, hasDebugAdapterExecutable: boolean, handle: number): TPromise<void> {
const provider = <IDebugConfigurationProvider>{
type: debugType
......@@ -163,6 +163,11 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape {
return this._proxy.$resolveDebugConfiguration(handle, folder, debugConfiguration);
};
}
if (hasDebugAdapterExecutable) {
provider.debugAdapterExecutable = (folder) => {
return this._proxy.$debugAdapterExecutable(handle, folder);
};
}
this.debugService.getConfigurationManager().registerDebugConfigurationProvider(handle, provider);
return TPromise.wrap<void>(undefined);
......
......@@ -576,6 +576,7 @@ export function createApiFactory(
CompletionItemKind: extHostTypes.CompletionItemKind,
CompletionList: extHostTypes.CompletionList,
CompletionTriggerKind: extHostTypes.CompletionTriggerKind,
DebugAdapterExecutable: extHostTypes.DebugAdapterExecutable,
Diagnostic: extHostTypes.Diagnostic,
DiagnosticSeverity: extHostTypes.DiagnosticSeverity,
Disposable: extHostTypes.Disposable,
......
......@@ -24,7 +24,7 @@ import * as editorCommon from 'vs/editor/common/editorCommon';
import * as modes from 'vs/editor/common/modes';
import { IConfigurationData, ConfigurationTarget, IConfigurationModel } from 'vs/platform/configuration/common/configuration';
import { IConfig } from 'vs/workbench/parts/debug/common/debug';
import { IConfig, IAdapterExecutable } from 'vs/workbench/parts/debug/common/debug';
import { IPickOpenEntry, IPickOptions } from 'vs/platform/quickOpen/common/quickOpen';
import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
......@@ -437,7 +437,7 @@ export interface MainThreadSCMShape extends IDisposable {
export type DebugSessionUUID = string;
export interface MainThreadDebugServiceShape extends IDisposable {
$registerDebugConfigurationProvider(type: string, hasProvideMethod: boolean, hasResolveMethod: boolean, handle: number): TPromise<any>;
$registerDebugConfigurationProvider(type: string, hasProvideMethod: boolean, hasResolveMethod: boolean, hasDebugAdapterExecutable: boolean, handle: number): TPromise<any>;
$unregisterDebugConfigurationProvider(handle: number): TPromise<any>;
$startDebugging(folder: UriComponents | undefined, nameOrConfig: string | vscode.DebugConfiguration): TPromise<boolean>;
$customDebugAdapterRequest(id: DebugSessionUUID, command: string, args: any): TPromise<any>;
......@@ -742,6 +742,7 @@ export interface ISourceMultiBreakpointDto {
export interface ExtHostDebugServiceShape {
$resolveDebugConfiguration(handle: number, folder: UriComponents | undefined, debugConfiguration: IConfig): TPromise<IConfig>;
$provideDebugConfigurations(handle: number, folder: UriComponents | undefined): TPromise<IConfig[]>;
$debugAdapterExecutable(handle: number, folder: UriComponents | undefined): TPromise<IAdapterExecutable>;
$acceptDebugSessionStarted(id: DebugSessionUUID, type: string, name: string): void;
$acceptDebugSessionTerminated(id: DebugSessionUUID, type: string, name: string): void;
$acceptDebugSessionActiveChanged(id: DebugSessionUUID | undefined, type?: string, name?: string): void;
......
......@@ -263,7 +263,10 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
let handle = this.nextHandle();
this._handlers.set(handle, provider);
this._debugServiceProxy.$registerDebugConfigurationProvider(type, !!provider.provideDebugConfigurations, !!provider.resolveDebugConfiguration, handle);
this._debugServiceProxy.$registerDebugConfigurationProvider(type,
!!provider.provideDebugConfigurations,
!!provider.resolveDebugConfiguration,
!!provider.debugAdapterExecutable, handle);
return new Disposable(() => {
this._handlers.delete(handle);
......@@ -293,6 +296,17 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
return asWinJsPromise(token => handler.resolveDebugConfiguration(this.getFolder(folderUri), debugConfiguration, token));
}
public $debugAdapterExecutable(handle: number, folderUri: UriComponents | undefined): TPromise<vscode.DebugAdapterExecutable> {
let handler = this._handlers.get(handle);
if (!handler) {
return TPromise.wrapError<vscode.DebugAdapterExecutable>(new Error('no handler found'));
}
if (!handler.debugAdapterExecutable) {
return TPromise.wrapError<vscode.DebugAdapterExecutable>(new Error('handler has no method debugAdapterExecutable'));
}
return asWinJsPromise(token => handler.debugAdapterExecutable(this.getFolder(folderUri), token));
}
public startDebugging(folder: vscode.WorkspaceFolder | undefined, nameOrConfig: string | vscode.DebugConfiguration): TPromise<boolean> {
return this._debugServiceProxy.$startDebugging(folder ? folder.uri : undefined, nameOrConfig);
}
......
......@@ -1610,6 +1610,16 @@ export class FunctionBreakpoint extends Breakpoint {
}
}
export class DebugAdapterExecutable implements vscode.DebugAdapterExecutable {
readonly command: string;
readonly args: string[];
constructor(command: string, args?: string[]) {
this.command = command;
this.args = args;
}
}
export enum LogLevel {
Trace = 1,
Debug = 2,
......
......@@ -402,6 +402,7 @@ export interface IDebugConfigurationProvider {
handle: number;
resolveDebugConfiguration?(folderUri: uri | undefined, debugConfiguration: IConfig): TPromise<IConfig>;
provideDebugConfigurations?(folderUri: uri | undefined): TPromise<IConfig[]>;
debugAdapterExecutable(folderUri: uri | undefined): TPromise<IAdapterExecutable>;
}
export interface IConfigurationManager {
......@@ -428,7 +429,9 @@ export interface IConfigurationManager {
registerDebugConfigurationProvider(handle: number, debugConfigurationProvider: IDebugConfigurationProvider): void;
unregisterDebugConfigurationProvider(handle: number): void;
resolveConfigurationByProviders(folderUri: uri | undefined, type: string | undefined, debugConfiguration: any): TPromise<any>;
debugAdapterExecutable(folderUri: uri | undefined, type: string): TPromise<IAdapterExecutable> | undefined;
}
export interface ILaunch {
......
......@@ -27,7 +27,7 @@ import { IFileService } from 'vs/platform/files/common/files';
import { IWorkspaceContextService, IWorkspaceFolder, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IDebugConfigurationProvider, IRawAdapter, ICompound, IDebugConfiguration, IConfig, IEnvConfig, IGlobalConfig, IConfigurationManager, ILaunch } from 'vs/workbench/parts/debug/common/debug';
import { IDebugConfigurationProvider, IRawAdapter, ICompound, IDebugConfiguration, IConfig, IEnvConfig, IGlobalConfig, IConfigurationManager, ILaunch, IAdapterExecutable } from 'vs/workbench/parts/debug/common/debug';
import { Adapter } from 'vs/workbench/parts/debug/node/debugAdapter';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
......@@ -291,6 +291,14 @@ export class ConfigurationManager implements IConfigurationManager {
.then(results => results.reduce((first, second) => first.concat(second), []));
}
public debugAdapterExecutable(folderUri: uri | undefined, type: string): TPromise<IAdapterExecutable> | undefined {
const providers = this.providers.filter(p => p.type === type && p.debugAdapterExecutable);
if (providers.length === 1) {
return providers[0].debugAdapterExecutable(folderUri);
}
return undefined;
}
private registerListeners(lifecycleService: ILifecycleService): void {
debuggersExtPoint.setHandler((extensions) => {
extensions.forEach(extension => {
......@@ -308,7 +316,7 @@ export class ConfigurationManager implements IConfigurationManager {
if (duplicate) {
duplicate.merge(rawAdapter, extension.description);
} else {
this.adapters.push(new Adapter(rawAdapter, extension.description, this.configurationService, this.commandService));
this.adapters.push(new Adapter(this, rawAdapter, extension.description, this.configurationService, this.commandService));
}
});
});
......
......@@ -13,14 +13,14 @@ import * as paths from 'vs/base/common/paths';
import * as platform from 'vs/base/common/platform';
import { IJSONSchema, IJSONSchemaSnippet } from 'vs/base/common/jsonSchema';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { IConfig, IRawAdapter, IAdapterExecutable, INTERNAL_CONSOLE_OPTIONS_SCHEMA } from 'vs/workbench/parts/debug/common/debug';
import { IConfig, IRawAdapter, IAdapterExecutable, INTERNAL_CONSOLE_OPTIONS_SCHEMA, IConfigurationManager } from 'vs/workbench/parts/debug/common/debug';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ICommandService } from 'vs/platform/commands/common/commands';
export class Adapter {
constructor(private rawAdapter: IRawAdapter, public extensionDescription: IExtensionDescription,
constructor(private configurationManager: IConfigurationManager, private rawAdapter: IRawAdapter, public extensionDescription: IExtensionDescription,
@IConfigurationService private configurationService: IConfigurationService,
@ICommandService private commandService: ICommandService
) {
......@@ -33,12 +33,24 @@ export class Adapter {
public getAdapterExecutable(root: IWorkspaceFolder, verifyAgainstFS = true): TPromise<IAdapterExecutable> {
// start with extension API
if (this.configurationManager) {
const adapterExecutablePromise = this.configurationManager.debugAdapterExecutable(root.uri, this.rawAdapter.type);
if (adapterExecutablePromise) {
return adapterExecutablePromise.then(adapterExecutable => {
return this.verifyAdapterDetails(adapterExecutable, verifyAgainstFS);
});
}
}
// try deprecated command based extension API
if (this.rawAdapter.adapterExecutableCommand && root) {
return this.commandService.executeCommand<IAdapterExecutable>(this.rawAdapter.adapterExecutableCommand, root.uri.toString()).then(ad => {
return this.verifyAdapterDetails(ad, verifyAgainstFS);
});
}
// old style: executable contribution specified in package.json
const adapterExecutable = <IAdapterExecutable>{
command: this.getProgram(),
args: this.getAttributeBasedOnPlatform('args')
......
......@@ -43,7 +43,7 @@ suite('Debug - Adapter', () => {
};
setup(() => {
adapter = new Adapter(rawAdapter, { extensionFolderPath, id: 'adapter', name: 'myAdapter', version: '1.0.0', publisher: 'vscode', isBuiltin: false, engines: null },
adapter = new Adapter(null, rawAdapter, { extensionFolderPath, id: 'adapter', name: 'myAdapter', version: '1.0.0', publisher: 'vscode', isBuiltin: false, engines: null },
new TestConfigurationService(), null);
});
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册