mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-26 10:16:01 +01:00
pass config to adapterExecutableCommand; fixes #45220
This commit is contained in:
Vendored
+30
@@ -437,6 +437,9 @@ declare module 'vscode' {
|
||||
* Represents a debug adapter executable and optional arguments passed to it.
|
||||
*/
|
||||
export class DebugAdapterExecutable {
|
||||
|
||||
readonly type: 'executable';
|
||||
|
||||
/**
|
||||
* The command path of the debug adapter executable.
|
||||
* A command must be either an absolute path or the name of an executable looked up via the PATH environment variable.
|
||||
@@ -455,6 +458,23 @@ declare module 'vscode' {
|
||||
constructor(command: string, args?: string[]);
|
||||
}
|
||||
|
||||
export class DebugAdapterServer {
|
||||
|
||||
readonly type: 'server';
|
||||
|
||||
/**
|
||||
* The port.
|
||||
*/
|
||||
readonly port: number;
|
||||
|
||||
/**
|
||||
* Create a new debug adapter specification.
|
||||
*/
|
||||
constructor(port: number);
|
||||
}
|
||||
|
||||
export type DebugAdapterDescriptor = DebugAdapterExecutable | DebugAdapterServer;
|
||||
|
||||
export interface DebugConfigurationProvider {
|
||||
/**
|
||||
* This optional method is called just before a debug adapter is started to determine its executable path and arguments.
|
||||
@@ -462,8 +482,18 @@ declare module 'vscode' {
|
||||
* @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.
|
||||
* @deprecated Use DebugConfigurationProvider.provideDebugAdapter instead
|
||||
*/
|
||||
debugAdapterExecutable?(folder: WorkspaceFolder | undefined, token?: CancellationToken): ProviderResult<DebugAdapterExecutable>;
|
||||
|
||||
/**
|
||||
* This optional method is called just before a debug adapter is started to determine its executable path and arguments.
|
||||
* Registering more than one provideDebugAdapter 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 descriptor](#DebugAdapterDescriptor) or undefined.
|
||||
*/
|
||||
provideDebugAdapter?(session: DebugSession, folder: WorkspaceFolder | undefined, executable: DebugAdapterExecutable, config: DebugConfiguration, token?: CancellationToken): ProviderResult<DebugAdapterDescriptor>;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { URI as uri } from 'vs/base/common/uri';
|
||||
import { IDebugService, IConfig, IDebugConfigurationProvider, IBreakpoint, IFunctionBreakpoint, IBreakpointData, IAdapterExecutable, ITerminalSettings, IDebugAdapter, IDebugAdapterProvider } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { IDebugService, IConfig, IDebugConfigurationProvider, IBreakpoint, IFunctionBreakpoint, IBreakpointData, ITerminalSettings, IDebugAdapter, IDebugAdapterProvider, IDebugSession } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import {
|
||||
ExtHostContext, ExtHostDebugServiceShape, MainThreadDebugServiceShape, DebugSessionUUID, MainContext,
|
||||
IExtHostContext, IBreakpointsDeltaDto, ISourceMultiBreakpointDto, ISourceBreakpointDto, IFunctionBreakpointDto
|
||||
IExtHostContext, IBreakpointsDeltaDto, ISourceMultiBreakpointDto, ISourceBreakpointDto, IFunctionBreakpointDto, IDebugSessionDto
|
||||
} from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||
import severity from 'vs/base/common/severity';
|
||||
@@ -36,33 +36,31 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDebugService);
|
||||
this._toDispose = [];
|
||||
this._toDispose.push(debugService.onDidNewSession(session => {
|
||||
this._proxy.$acceptDebugSessionStarted(<DebugSessionUUID>session.getId(), session.configuration.type, session.getName(false));
|
||||
this._proxy.$acceptDebugSessionStarted(this.getSessionDto(session));
|
||||
}));
|
||||
// Need to start listening early to new session events because a custom event can come while a session is initialising
|
||||
this._toDispose.push(debugService.onWillNewSession(session => {
|
||||
this._toDispose.push(session.onDidCustomEvent(event => this._proxy.$acceptDebugSessionCustomEvent(session.getId(), session.configuration.type, session.configuration.name, event)));
|
||||
this._toDispose.push(session.onDidCustomEvent(event => this._proxy.$acceptDebugSessionCustomEvent(this.getSessionDto(session), event)));
|
||||
}));
|
||||
this._toDispose.push(debugService.onDidEndSession(session => {
|
||||
this._proxy.$acceptDebugSessionTerminated(<DebugSessionUUID>session.getId(), session.configuration.type, session.getName(false));
|
||||
this._proxy.$acceptDebugSessionTerminated(this.getSessionDto(session));
|
||||
}));
|
||||
this._toDispose.push(debugService.getViewModel().onDidFocusSession(proc => {
|
||||
if (proc) {
|
||||
this._proxy.$acceptDebugSessionActiveChanged(<DebugSessionUUID>proc.getId(), proc.configuration.type, proc.getName(false));
|
||||
} else {
|
||||
this._proxy.$acceptDebugSessionActiveChanged(undefined);
|
||||
}
|
||||
this._toDispose.push(debugService.getViewModel().onDidFocusSession(session => {
|
||||
this._proxy.$acceptDebugSessionActiveChanged(this.getSessionDto(session));
|
||||
}));
|
||||
|
||||
this._debugAdapters = new Map<number, ExtensionHostDebugAdapter>();
|
||||
}
|
||||
|
||||
public $registerDebugTypes(debugTypes: string[]) {
|
||||
this._toDispose.push(this.debugService.getConfigurationManager().registerDebugAdapterProvider(debugTypes, this));
|
||||
public dispose(): void {
|
||||
this._toDispose = dispose(this._toDispose);
|
||||
}
|
||||
|
||||
createDebugAdapter(debugType: string, adapterInfo, debugPort: number): IDebugAdapter {
|
||||
// interface IDebugAdapterProvider
|
||||
|
||||
createDebugAdapter(session: IDebugSession, folder: IWorkspaceFolder, config: IConfig): IDebugAdapter {
|
||||
const handle = this._debugAdaptersHandleCounter++;
|
||||
const da = new ExtensionHostDebugAdapter(handle, this._proxy, debugType, adapterInfo, debugPort);
|
||||
const da = new ExtensionHostDebugAdapter(handle, this._proxy, this.getSessionDto(session), folder, config);
|
||||
this._debugAdapters.set(handle, da);
|
||||
return da;
|
||||
}
|
||||
@@ -75,8 +73,11 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
|
||||
return TPromise.wrap(this._proxy.$runInTerminal(args, config));
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._toDispose = dispose(this._toDispose);
|
||||
|
||||
// RPC methods (MainThreadDebugServiceShape)
|
||||
|
||||
public $registerDebugTypes(debugTypes: string[]) {
|
||||
this._toDispose.push(this.debugService.getConfigurationManager().registerDebugAdapterProvider(debugTypes, this));
|
||||
}
|
||||
|
||||
public $startBreakpointEvents(): Thenable<void> {
|
||||
@@ -147,54 +148,25 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
|
||||
return void 0;
|
||||
}
|
||||
|
||||
private convertToDto(bps: (ReadonlyArray<IBreakpoint | IFunctionBreakpoint>)): (ISourceBreakpointDto | IFunctionBreakpointDto)[] {
|
||||
return bps.map(bp => {
|
||||
if ('name' in bp) {
|
||||
const fbp = <IFunctionBreakpoint>bp;
|
||||
return <IFunctionBreakpointDto>{
|
||||
type: 'function',
|
||||
id: fbp.getId(),
|
||||
enabled: fbp.enabled,
|
||||
condition: fbp.condition,
|
||||
hitCondition: fbp.hitCondition,
|
||||
logMessage: fbp.logMessage,
|
||||
functionName: fbp.name
|
||||
};
|
||||
} else {
|
||||
const sbp = <IBreakpoint>bp;
|
||||
return <ISourceBreakpointDto>{
|
||||
type: 'source',
|
||||
id: sbp.getId(),
|
||||
enabled: sbp.enabled,
|
||||
condition: sbp.condition,
|
||||
hitCondition: sbp.hitCondition,
|
||||
logMessage: sbp.logMessage,
|
||||
uri: sbp.uri,
|
||||
line: sbp.lineNumber > 0 ? sbp.lineNumber - 1 : 0,
|
||||
character: (typeof sbp.column === 'number' && sbp.column > 0) ? sbp.column - 1 : 0,
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public $registerDebugConfigurationProvider(debugType: string, hasProvide: boolean, hasResolve: boolean, hasDebugAdapterExecutable: boolean, handle: number): Thenable<void> {
|
||||
public $registerDebugConfigurationProvider(debugType: string, hasProvide: boolean, hasResolve: boolean, hasProvideDebugAdapter: boolean, handle: number): Thenable<void> {
|
||||
|
||||
const provider = <IDebugConfigurationProvider>{
|
||||
type: debugType
|
||||
};
|
||||
if (hasProvide) {
|
||||
provider.provideDebugConfigurations = folder => {
|
||||
provider.provideDebugConfigurations = (folder) => {
|
||||
return TPromise.wrap(this._proxy.$provideDebugConfigurations(handle, folder));
|
||||
};
|
||||
}
|
||||
if (hasResolve) {
|
||||
provider.resolveDebugConfiguration = (folder, debugConfiguration) => {
|
||||
return TPromise.wrap(this._proxy.$resolveDebugConfiguration(handle, folder, debugConfiguration));
|
||||
provider.resolveDebugConfiguration = (folder, config) => {
|
||||
return TPromise.wrap(this._proxy.$resolveDebugConfiguration(handle, folder, config));
|
||||
};
|
||||
}
|
||||
if (hasDebugAdapterExecutable) {
|
||||
provider.debugAdapterExecutable = (folder) => {
|
||||
return TPromise.wrap(this._proxy.$debugAdapterExecutable(handle, folder));
|
||||
if (hasProvideDebugAdapter) {
|
||||
provider.provideDebugAdapter = (session, folder, config) => {
|
||||
return TPromise.wrap(this._proxy.$provideDebugAdapter(handle, this.getSessionDto(session), folder, config));
|
||||
};
|
||||
}
|
||||
this.debugService.getConfigurationManager().registerDebugConfigurationProvider(handle, provider);
|
||||
@@ -255,6 +227,49 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
|
||||
public $acceptDAExit(handle: number, code: number, signal: string) {
|
||||
this._debugAdapters.get(handle).fireExit(handle, code, signal);
|
||||
}
|
||||
|
||||
// dto helpers
|
||||
|
||||
private getSessionDto(session: IDebugSession): IDebugSessionDto {
|
||||
if (session) {
|
||||
return {
|
||||
id: <DebugSessionUUID>session.getId(),
|
||||
type: session.configuration.type,
|
||||
name: session.getName(false)
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private convertToDto(bps: (ReadonlyArray<IBreakpoint | IFunctionBreakpoint>)): (ISourceBreakpointDto | IFunctionBreakpointDto)[] {
|
||||
return bps.map(bp => {
|
||||
if ('name' in bp) {
|
||||
const fbp = <IFunctionBreakpoint>bp;
|
||||
return <IFunctionBreakpointDto>{
|
||||
type: 'function',
|
||||
id: fbp.getId(),
|
||||
enabled: fbp.enabled,
|
||||
condition: fbp.condition,
|
||||
hitCondition: fbp.hitCondition,
|
||||
logMessage: fbp.logMessage,
|
||||
functionName: fbp.name
|
||||
};
|
||||
} else {
|
||||
const sbp = <IBreakpoint>bp;
|
||||
return <ISourceBreakpointDto>{
|
||||
type: 'source',
|
||||
id: sbp.getId(),
|
||||
enabled: sbp.enabled,
|
||||
condition: sbp.condition,
|
||||
hitCondition: sbp.hitCondition,
|
||||
logMessage: sbp.logMessage,
|
||||
uri: sbp.uri,
|
||||
line: sbp.lineNumber > 0 ? sbp.lineNumber - 1 : 0,
|
||||
character: (typeof sbp.column === 'number' && sbp.column > 0) ? sbp.column - 1 : 0,
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -262,7 +277,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
|
||||
*/
|
||||
class ExtensionHostDebugAdapter extends AbstractDebugAdapter {
|
||||
|
||||
constructor(private _handle: number, private _proxy: ExtHostDebugServiceShape, private _debugType: string, private _adapterExecutable: IAdapterExecutable | null, private _debugPort: number) {
|
||||
constructor(private _handle: number, private _proxy: ExtHostDebugServiceShape, private _sessionDto: IDebugSessionDto, private folder: IWorkspaceFolder, private config: IConfig) {
|
||||
super();
|
||||
}
|
||||
|
||||
@@ -275,7 +290,7 @@ class ExtensionHostDebugAdapter extends AbstractDebugAdapter {
|
||||
}
|
||||
|
||||
public startSession(): TPromise<void> {
|
||||
return TPromise.wrap(this._proxy.$startDASession(this._handle, this._debugType, this._adapterExecutable, this._debugPort));
|
||||
return TPromise.wrap(this._proxy.$startDASession(this._handle, this._sessionDto, this.folder ? this.folder.uri : undefined, this.config));
|
||||
}
|
||||
|
||||
public sendMessage(message: DebugProtocol.ProtocolMessage): void {
|
||||
|
||||
@@ -725,6 +725,7 @@ export function createApiFactory(
|
||||
CompletionTriggerKind: extHostTypes.CompletionTriggerKind,
|
||||
ConfigurationTarget: extHostTypes.ConfigurationTarget,
|
||||
DebugAdapterExecutable: extHostTypes.DebugAdapterExecutable,
|
||||
DebugAdapterServer: extHostTypes.DebugAdapterServer,
|
||||
DecorationRangeBehavior: extHostTypes.DecorationRangeBehavior,
|
||||
Diagnostic: extHostTypes.Diagnostic,
|
||||
DiagnosticRelatedInformation: extHostTypes.DiagnosticRelatedInformation,
|
||||
|
||||
@@ -33,7 +33,7 @@ import { EndOfLine, IFileOperationOptions, TextEditorLineNumbersStyle } from 'vs
|
||||
import { EditorViewColumn } from 'vs/workbench/api/shared/editor';
|
||||
import { TaskDTO, TaskExecutionDTO, TaskFilterDTO, TaskHandleDTO, TaskProcessEndedDTO, TaskProcessStartedDTO, TaskSystemInfoDTO } from 'vs/workbench/api/shared/tasks';
|
||||
import { ITreeItem } from 'vs/workbench/common/views';
|
||||
import { IAdapterExecutable, IConfig, ITerminalSettings } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { IConfig, ITerminalSettings, IAdapterDescriptor } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { TaskSet } from 'vs/workbench/parts/tasks/common/tasks';
|
||||
import { ITerminalDimensions } from 'vs/workbench/parts/terminal/common/terminal';
|
||||
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||
@@ -943,20 +943,26 @@ export interface ISourceMultiBreakpointDto {
|
||||
}[];
|
||||
}
|
||||
|
||||
export interface IDebugSessionDto {
|
||||
id: DebugSessionUUID;
|
||||
type: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface ExtHostDebugServiceShape {
|
||||
$substituteVariables(folder: UriComponents | undefined, config: IConfig): Thenable<IConfig>;
|
||||
$runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): Thenable<void>;
|
||||
$startDASession(handle: number, debugType: string, adapterExecutableInfo: IAdapterExecutable | null, debugPort: number): Thenable<void>;
|
||||
$startDASession(handle: number, session: IDebugSessionDto, folder: UriComponents | undefined, debugConfiguration: IConfig): Thenable<void>;
|
||||
$stopDASession(handle: number): Thenable<void>;
|
||||
$sendDAMessage(handle: number, message: DebugProtocol.ProtocolMessage): void;
|
||||
$resolveDebugConfiguration(handle: number, folder: UriComponents | undefined, debugConfiguration: IConfig): Thenable<IConfig>;
|
||||
$provideDebugConfigurations(handle: number, folder: UriComponents | undefined): Thenable<IConfig[]>;
|
||||
$debugAdapterExecutable(handle: number, folder: UriComponents | undefined): Thenable<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;
|
||||
$acceptDebugSessionCustomEvent(id: DebugSessionUUID, type: string, name: string, event: any): void;
|
||||
$acceptBreakpointsDelta(delat: IBreakpointsDeltaDto): void;
|
||||
$provideDebugAdapter(handle: number, session: IDebugSessionDto, folderUri: UriComponents | undefined, debugConfiguration: IConfig): Thenable<IAdapterDescriptor>;
|
||||
$acceptDebugSessionStarted(session: IDebugSessionDto): void;
|
||||
$acceptDebugSessionTerminated(session: IDebugSessionDto): void;
|
||||
$acceptDebugSessionActiveChanged(session: IDebugSessionDto): void;
|
||||
$acceptDebugSessionCustomEvent(session: IDebugSessionDto, event: any): void;
|
||||
$acceptBreakpointsDelta(delta: IBreakpointsDeltaDto): void;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -13,16 +13,16 @@ import { asThenable } from 'vs/base/common/async';
|
||||
import * as nls from 'vs/nls';
|
||||
import {
|
||||
MainContext, MainThreadDebugServiceShape, ExtHostDebugServiceShape, DebugSessionUUID,
|
||||
IMainContext, IBreakpointsDeltaDto, ISourceMultiBreakpointDto, IFunctionBreakpointDto
|
||||
IMainContext, IBreakpointsDeltaDto, ISourceMultiBreakpointDto, IFunctionBreakpointDto, IDebugSessionDto
|
||||
} from 'vs/workbench/api/node/extHost.protocol';
|
||||
import * as vscode from 'vscode';
|
||||
import { Disposable, Position, Location, SourceBreakpoint, FunctionBreakpoint } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { Disposable, Position, Location, SourceBreakpoint, FunctionBreakpoint, DebugAdapterServer } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { DebugAdapter, StreamDebugAdapter, SocketDebugAdapter } from 'vs/workbench/parts/debug/node/debugAdapter';
|
||||
import { DebugAdapter, SocketDebugAdapter } from 'vs/workbench/parts/debug/node/debugAdapter';
|
||||
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
|
||||
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
|
||||
import { IAdapterExecutable, ITerminalSettings, IDebuggerContribution, IConfig, IDebugAdapter } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { ITerminalSettings, IDebuggerContribution, IConfig, IDebugAdapter } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { getTerminalLauncher, hasChildprocesses, prepareCommand } from 'vs/workbench/parts/debug/node/terminals';
|
||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/node/variableResolver';
|
||||
@@ -37,7 +37,8 @@ import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
export class ExtHostDebugService implements ExtHostDebugServiceShape {
|
||||
|
||||
private _handleCounter: number;
|
||||
private _handlers: Map<number, vscode.DebugConfigurationProvider>;
|
||||
private _providerByHandle: Map<number, vscode.DebugConfigurationProvider>;
|
||||
private _providerByType: Map<string, vscode.DebugConfigurationProvider>;
|
||||
|
||||
private _debugServiceProxy: MainThreadDebugServiceShape;
|
||||
private _debugSessions: Map<DebugSessionUUID, ExtHostDebugSession> = new Map<DebugSessionUUID, ExtHostDebugSession>();
|
||||
@@ -82,7 +83,8 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
|
||||
) {
|
||||
|
||||
this._handleCounter = 0;
|
||||
this._handlers = new Map<number, vscode.DebugConfigurationProvider>();
|
||||
this._providerByHandle = new Map();
|
||||
this._providerByType = new Map();
|
||||
|
||||
this._onDidStartDebugSession = new Emitter<vscode.DebugSession>();
|
||||
this._onDidTerminateDebugSession = new Emitter<vscode.DebugSession>();
|
||||
@@ -124,143 +126,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
|
||||
}
|
||||
}
|
||||
|
||||
public $runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): TPromise<void> {
|
||||
|
||||
if (args.kind === 'integrated') {
|
||||
|
||||
if (!this._terminalDisposedListener) {
|
||||
// React on terminal disposed and check if that is the debug terminal #12956
|
||||
this._terminalDisposedListener = this._terminalService.onDidCloseTerminal(terminal => {
|
||||
if (this._integratedTerminalInstance && this._integratedTerminalInstance === terminal) {
|
||||
this._integratedTerminalInstance = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return new TPromise(resolve => {
|
||||
if (this._integratedTerminalInstance) {
|
||||
this._integratedTerminalInstance.processId.then(pid => {
|
||||
resolve(hasChildprocesses(pid));
|
||||
}, err => {
|
||||
resolve(true);
|
||||
});
|
||||
} else {
|
||||
resolve(true);
|
||||
}
|
||||
}).then(needNewTerminal => {
|
||||
|
||||
if (needNewTerminal) {
|
||||
this._integratedTerminalInstance = this._terminalService.createTerminal(args.title || nls.localize('debug.terminal.title', "debuggee"));
|
||||
}
|
||||
|
||||
this._integratedTerminalInstance.show();
|
||||
|
||||
return new TPromise((resolve, error) => {
|
||||
setTimeout(_ => {
|
||||
const command = prepareCommand(args, config);
|
||||
this._integratedTerminalInstance.sendText(command, true);
|
||||
resolve(void 0);
|
||||
}, 500);
|
||||
});
|
||||
});
|
||||
|
||||
} else if (args.kind === 'external') {
|
||||
|
||||
const terminalLauncher = getTerminalLauncher();
|
||||
if (terminalLauncher) {
|
||||
return terminalLauncher.runInTerminal(args, config);
|
||||
}
|
||||
}
|
||||
return void 0;
|
||||
}
|
||||
|
||||
public $substituteVariables(folderUri: UriComponents | undefined, config: IConfig): TPromise<IConfig> {
|
||||
if (!this._variableResolver) {
|
||||
this._variableResolver = new ExtHostVariableResolverService(this._workspaceService, this._editorsService, this._configurationService);
|
||||
}
|
||||
let ws: IWorkspaceFolder;
|
||||
const folder = this.getFolder(folderUri);
|
||||
if (folder) {
|
||||
ws = {
|
||||
uri: folder.uri,
|
||||
name: folder.name,
|
||||
index: folder.index,
|
||||
toResource: () => {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
};
|
||||
}
|
||||
return TPromise.wrap(this._variableResolver.resolveAny(ws, config));
|
||||
}
|
||||
|
||||
public $startDASession(handle: number, debugType: string, adpaterExecutable: IAdapterExecutable | null, debugPort: number): TPromise<void> {
|
||||
const mythis = this;
|
||||
|
||||
let da: StreamDebugAdapter = null;
|
||||
|
||||
if (debugPort > 0) {
|
||||
da = new class extends SocketDebugAdapter {
|
||||
|
||||
// DA -> VS Code
|
||||
public acceptMessage(message: DebugProtocol.ProtocolMessage) {
|
||||
convertToVSCPaths(message, source => {
|
||||
if (paths.isAbsolute(source.path)) {
|
||||
(<any>source).path = URI.file(source.path);
|
||||
}
|
||||
});
|
||||
mythis._debugServiceProxy.$acceptDAMessage(handle, message);
|
||||
}
|
||||
|
||||
}(debugPort);
|
||||
|
||||
} else {
|
||||
da = new class extends DebugAdapter {
|
||||
|
||||
// DA -> VS Code
|
||||
public acceptMessage(message: DebugProtocol.ProtocolMessage) {
|
||||
convertToVSCPaths(message, source => {
|
||||
if (paths.isAbsolute(source.path)) {
|
||||
(<any>source).path = URI.file(source.path);
|
||||
}
|
||||
});
|
||||
mythis._debugServiceProxy.$acceptDAMessage(handle, message);
|
||||
}
|
||||
|
||||
}(debugType, adpaterExecutable, this._extensionService.getAllExtensionDescriptions());
|
||||
}
|
||||
|
||||
this._debugAdapters.set(handle, da);
|
||||
da.onError(err => this._debugServiceProxy.$acceptDAError(handle, err.name, err.message, err.stack));
|
||||
da.onExit(code => this._debugServiceProxy.$acceptDAExit(handle, code, null));
|
||||
return da.startSession();
|
||||
}
|
||||
|
||||
public $sendDAMessage(handle: number, message: DebugProtocol.ProtocolMessage): TPromise<void> {
|
||||
// VS Code -> DA
|
||||
convertToDAPaths(message, source => {
|
||||
if (typeof source.path === 'object') {
|
||||
source.path = URI.revive(source.path).fsPath;
|
||||
}
|
||||
});
|
||||
const da = this._debugAdapters.get(handle);
|
||||
if (da) {
|
||||
da.sendMessage(message);
|
||||
}
|
||||
return void 0;
|
||||
}
|
||||
|
||||
public $stopDASession(handle: number): TPromise<void> {
|
||||
const da = this._debugAdapters.get(handle);
|
||||
this._debugAdapters.delete(handle);
|
||||
return da ? da.stopSession() : void 0;
|
||||
}
|
||||
|
||||
private startBreakpoints() {
|
||||
if (!this._breakpointEventsActive) {
|
||||
this._breakpointEventsActive = true;
|
||||
this._debugServiceProxy.$startBreakpointEvents();
|
||||
}
|
||||
}
|
||||
// extension debug API
|
||||
|
||||
get onDidChangeBreakpoints(): Event<vscode.BreakpointsChangeEvent> {
|
||||
return this._onDidChangeBreakpoints.event;
|
||||
@@ -275,67 +141,6 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
|
||||
return result;
|
||||
}
|
||||
|
||||
public $acceptBreakpointsDelta(delta: IBreakpointsDeltaDto): void {
|
||||
|
||||
let a: vscode.Breakpoint[] = [];
|
||||
let r: vscode.Breakpoint[] = [];
|
||||
let c: vscode.Breakpoint[] = [];
|
||||
|
||||
if (delta.added) {
|
||||
for (const bpd of delta.added) {
|
||||
|
||||
if (!this._breakpoints.has(bpd.id)) {
|
||||
let bp: vscode.Breakpoint;
|
||||
if (bpd.type === 'function') {
|
||||
bp = new FunctionBreakpoint(bpd.functionName, bpd.enabled, bpd.condition, bpd.hitCondition, bpd.logMessage);
|
||||
} else {
|
||||
const uri = URI.revive(bpd.uri);
|
||||
bp = new SourceBreakpoint(new Location(uri, new Position(bpd.line, bpd.character)), bpd.enabled, bpd.condition, bpd.hitCondition, bpd.logMessage);
|
||||
}
|
||||
bp['_id'] = bpd.id;
|
||||
this._breakpoints.set(bpd.id, bp);
|
||||
a.push(bp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (delta.removed) {
|
||||
for (const id of delta.removed) {
|
||||
const bp = this._breakpoints.get(id);
|
||||
if (bp) {
|
||||
this._breakpoints.delete(id);
|
||||
r.push(bp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (delta.changed) {
|
||||
for (const bpd of delta.changed) {
|
||||
let bp = this._breakpoints.get(bpd.id);
|
||||
if (bp) {
|
||||
if (bp instanceof FunctionBreakpoint && bpd.type === 'function') {
|
||||
const fbp = <any>bp;
|
||||
fbp.enabled = bpd.enabled;
|
||||
fbp.condition = bpd.condition;
|
||||
fbp.hitCondition = bpd.hitCondition;
|
||||
fbp.logMessage = bpd.logMessage;
|
||||
fbp.functionName = bpd.functionName;
|
||||
} else if (bp instanceof SourceBreakpoint && bpd.type === 'source') {
|
||||
const sbp = <any>bp;
|
||||
sbp.enabled = bpd.enabled;
|
||||
sbp.condition = bpd.condition;
|
||||
sbp.hitCondition = bpd.hitCondition;
|
||||
sbp.logMessage = bpd.logMessage;
|
||||
sbp.location = new Location(URI.revive(bpd.uri), new Position(bpd.line, bpd.character));
|
||||
}
|
||||
c.push(bp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.fireBreakpointChanges(a, r, c);
|
||||
}
|
||||
|
||||
public addBreakpoints(breakpoints0: vscode.Breakpoint[]): Thenable<void> {
|
||||
|
||||
this.startBreakpoints();
|
||||
@@ -424,6 +229,328 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
|
||||
return this._debugServiceProxy.$unregisterBreakpoints(ids, fids);
|
||||
}
|
||||
|
||||
public startDebugging(folder: vscode.WorkspaceFolder | undefined, nameOrConfig: string | vscode.DebugConfiguration): Thenable<boolean> {
|
||||
return this._debugServiceProxy.$startDebugging(folder ? folder.uri : undefined, nameOrConfig);
|
||||
}
|
||||
|
||||
public registerDebugConfigurationProvider(type: string, provider: vscode.DebugConfigurationProvider): vscode.Disposable {
|
||||
if (!provider) {
|
||||
return new Disposable(() => { });
|
||||
}
|
||||
|
||||
let handle = this._handleCounter++;
|
||||
this._providerByHandle.set(handle, provider);
|
||||
this._providerByType.set(type, provider);
|
||||
|
||||
this._debugServiceProxy.$registerDebugConfigurationProvider(type,
|
||||
!!provider.provideDebugConfigurations,
|
||||
!!provider.resolveDebugConfiguration,
|
||||
!!provider.debugAdapterExecutable || !!provider.provideDebugAdapter, handle);
|
||||
|
||||
return new Disposable(() => {
|
||||
this._providerByHandle.delete(handle);
|
||||
this._providerByType.delete(type); // TODO@AW support more than one
|
||||
this._debugServiceProxy.$unregisterDebugConfigurationProvider(handle);
|
||||
});
|
||||
}
|
||||
|
||||
// RPC methods (ExtHostDebugServiceShape)
|
||||
|
||||
public $runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): TPromise<void> {
|
||||
|
||||
if (args.kind === 'integrated') {
|
||||
|
||||
if (!this._terminalDisposedListener) {
|
||||
// React on terminal disposed and check if that is the debug terminal #12956
|
||||
this._terminalDisposedListener = this._terminalService.onDidCloseTerminal(terminal => {
|
||||
if (this._integratedTerminalInstance && this._integratedTerminalInstance === terminal) {
|
||||
this._integratedTerminalInstance = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return new TPromise(resolve => {
|
||||
if (this._integratedTerminalInstance) {
|
||||
this._integratedTerminalInstance.processId.then(pid => {
|
||||
resolve(hasChildprocesses(pid));
|
||||
}, err => {
|
||||
resolve(true);
|
||||
});
|
||||
} else {
|
||||
resolve(true);
|
||||
}
|
||||
}).then(needNewTerminal => {
|
||||
|
||||
if (needNewTerminal) {
|
||||
this._integratedTerminalInstance = this._terminalService.createTerminal(args.title || nls.localize('debug.terminal.title', "debuggee"));
|
||||
}
|
||||
|
||||
this._integratedTerminalInstance.show();
|
||||
|
||||
return new TPromise((resolve, error) => {
|
||||
setTimeout(_ => {
|
||||
const command = prepareCommand(args, config);
|
||||
this._integratedTerminalInstance.sendText(command, true);
|
||||
resolve(void 0);
|
||||
}, 500);
|
||||
});
|
||||
});
|
||||
|
||||
} else if (args.kind === 'external') {
|
||||
|
||||
const terminalLauncher = getTerminalLauncher();
|
||||
if (terminalLauncher) {
|
||||
return terminalLauncher.runInTerminal(args, config);
|
||||
}
|
||||
}
|
||||
return void 0;
|
||||
}
|
||||
|
||||
public $substituteVariables(folderUri: UriComponents | undefined, config: IConfig): TPromise<IConfig> {
|
||||
if (!this._variableResolver) {
|
||||
this._variableResolver = new ExtHostVariableResolverService(this._workspaceService, this._editorsService, this._configurationService);
|
||||
}
|
||||
let ws: IWorkspaceFolder;
|
||||
const folder = this.getFolder(folderUri);
|
||||
if (folder) {
|
||||
ws = {
|
||||
uri: folder.uri,
|
||||
name: folder.name,
|
||||
index: folder.index,
|
||||
toResource: () => {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
};
|
||||
}
|
||||
return TPromise.wrap(this._variableResolver.resolveAny(ws, config));
|
||||
}
|
||||
|
||||
public $startDASession(handle: number, sessionDto: IDebugSessionDto, folderUri: UriComponents | undefined, config: vscode.DebugConfiguration): TPromise<void> {
|
||||
const mythis = this;
|
||||
|
||||
return this.getAdapterDescriptor(this._providerByType.get(config.type), sessionDto, folderUri, config).then(adapter => {
|
||||
|
||||
let da: IDebugAdapter = undefined;
|
||||
|
||||
switch (adapter.type) {
|
||||
|
||||
case 'server':
|
||||
da = new class extends SocketDebugAdapter {
|
||||
|
||||
// DA -> VS Code
|
||||
public acceptMessage(message: DebugProtocol.ProtocolMessage) {
|
||||
convertToVSCPaths(message, source => {
|
||||
if (paths.isAbsolute(source.path)) {
|
||||
(<any>source).path = URI.file(source.path);
|
||||
}
|
||||
});
|
||||
mythis._debugServiceProxy.$acceptDAMessage(handle, message);
|
||||
}
|
||||
|
||||
}(adapter.port);
|
||||
break;
|
||||
|
||||
case 'executable':
|
||||
da = new class extends DebugAdapter {
|
||||
|
||||
// DA -> VS Code
|
||||
public acceptMessage(message: DebugProtocol.ProtocolMessage) {
|
||||
convertToVSCPaths(message, source => {
|
||||
if (paths.isAbsolute(source.path)) {
|
||||
(<any>source).path = URI.file(source.path);
|
||||
}
|
||||
});
|
||||
mythis._debugServiceProxy.$acceptDAMessage(handle, message);
|
||||
}
|
||||
|
||||
}(config.type, adapter);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (da) {
|
||||
this._debugAdapters.set(handle, da);
|
||||
da.onError(err => this._debugServiceProxy.$acceptDAError(handle, err.name, err.message, err.stack));
|
||||
da.onExit(code => this._debugServiceProxy.$acceptDAExit(handle, code, null));
|
||||
return da.startSession();
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
public $sendDAMessage(handle: number, message: DebugProtocol.ProtocolMessage): TPromise<void> {
|
||||
// VS Code -> DA
|
||||
convertToDAPaths(message, source => {
|
||||
if (typeof source.path === 'object') {
|
||||
source.path = URI.revive(source.path).fsPath;
|
||||
}
|
||||
});
|
||||
const da = this._debugAdapters.get(handle);
|
||||
if (da) {
|
||||
da.sendMessage(message);
|
||||
}
|
||||
return void 0;
|
||||
}
|
||||
|
||||
public $stopDASession(handle: number): TPromise<void> {
|
||||
const da = this._debugAdapters.get(handle);
|
||||
this._debugAdapters.delete(handle);
|
||||
return da ? da.stopSession() : void 0;
|
||||
}
|
||||
|
||||
|
||||
public $acceptBreakpointsDelta(delta: IBreakpointsDeltaDto): void {
|
||||
|
||||
let a: vscode.Breakpoint[] = [];
|
||||
let r: vscode.Breakpoint[] = [];
|
||||
let c: vscode.Breakpoint[] = [];
|
||||
|
||||
if (delta.added) {
|
||||
for (const bpd of delta.added) {
|
||||
|
||||
if (!this._breakpoints.has(bpd.id)) {
|
||||
let bp: vscode.Breakpoint;
|
||||
if (bpd.type === 'function') {
|
||||
bp = new FunctionBreakpoint(bpd.functionName, bpd.enabled, bpd.condition, bpd.hitCondition, bpd.logMessage);
|
||||
} else {
|
||||
const uri = URI.revive(bpd.uri);
|
||||
bp = new SourceBreakpoint(new Location(uri, new Position(bpd.line, bpd.character)), bpd.enabled, bpd.condition, bpd.hitCondition, bpd.logMessage);
|
||||
}
|
||||
bp['_id'] = bpd.id;
|
||||
this._breakpoints.set(bpd.id, bp);
|
||||
a.push(bp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (delta.removed) {
|
||||
for (const id of delta.removed) {
|
||||
const bp = this._breakpoints.get(id);
|
||||
if (bp) {
|
||||
this._breakpoints.delete(id);
|
||||
r.push(bp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (delta.changed) {
|
||||
for (const bpd of delta.changed) {
|
||||
let bp = this._breakpoints.get(bpd.id);
|
||||
if (bp) {
|
||||
if (bp instanceof FunctionBreakpoint && bpd.type === 'function') {
|
||||
const fbp = <any>bp;
|
||||
fbp.enabled = bpd.enabled;
|
||||
fbp.condition = bpd.condition;
|
||||
fbp.hitCondition = bpd.hitCondition;
|
||||
fbp.logMessage = bpd.logMessage;
|
||||
fbp.functionName = bpd.functionName;
|
||||
} else if (bp instanceof SourceBreakpoint && bpd.type === 'source') {
|
||||
const sbp = <any>bp;
|
||||
sbp.enabled = bpd.enabled;
|
||||
sbp.condition = bpd.condition;
|
||||
sbp.hitCondition = bpd.hitCondition;
|
||||
sbp.logMessage = bpd.logMessage;
|
||||
sbp.location = new Location(URI.revive(bpd.uri), new Position(bpd.line, bpd.character));
|
||||
}
|
||||
c.push(bp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.fireBreakpointChanges(a, r, c);
|
||||
}
|
||||
|
||||
|
||||
public $provideDebugConfigurations(handle: number, folderUri: UriComponents | undefined): Thenable<vscode.DebugConfiguration[]> {
|
||||
let provider = this._providerByHandle.get(handle);
|
||||
if (!provider) {
|
||||
return TPromise.wrapError<vscode.DebugConfiguration[]>(new Error('no handler found'));
|
||||
}
|
||||
if (!provider.provideDebugConfigurations) {
|
||||
return TPromise.wrapError<vscode.DebugConfiguration[]>(new Error('handler has no method provideDebugConfigurations'));
|
||||
}
|
||||
return asThenable(() => provider.provideDebugConfigurations(this.getFolder(folderUri), CancellationToken.None));
|
||||
}
|
||||
|
||||
public $resolveDebugConfiguration(handle: number, folderUri: UriComponents | undefined, debugConfiguration: vscode.DebugConfiguration): Thenable<vscode.DebugConfiguration> {
|
||||
let provider = this._providerByHandle.get(handle);
|
||||
if (!provider) {
|
||||
return TPromise.wrapError<vscode.DebugConfiguration>(new Error('no handler found'));
|
||||
}
|
||||
if (!provider.resolveDebugConfiguration) {
|
||||
return TPromise.wrapError<vscode.DebugConfiguration>(new Error('handler has no method resolveDebugConfiguration'));
|
||||
}
|
||||
return asThenable(() => provider.resolveDebugConfiguration(this.getFolder(folderUri), debugConfiguration, CancellationToken.None));
|
||||
}
|
||||
|
||||
public $provideDebugAdapter(handle: number, sessionDto: IDebugSessionDto, folderUri: UriComponents | undefined, config: vscode.DebugConfiguration): Thenable<vscode.DebugAdapterDescriptor> {
|
||||
let provider = this._providerByHandle.get(handle);
|
||||
if (!provider) {
|
||||
return TPromise.wrapError<vscode.DebugAdapterExecutable>(new Error('no handler found'));
|
||||
}
|
||||
if (!provider.debugAdapterExecutable && !provider.provideDebugAdapter) {
|
||||
return TPromise.wrapError<vscode.DebugAdapterExecutable>(new Error('handler has no methods provideDebugAdapter or debugAdapterExecutable'));
|
||||
}
|
||||
return this.getAdapterDescriptor(provider, this.getSession(sessionDto), folderUri, config);
|
||||
}
|
||||
|
||||
public $acceptDebugSessionStarted(sessionDto: IDebugSessionDto): void {
|
||||
|
||||
this._onDidStartDebugSession.fire(this.getSession(sessionDto));
|
||||
}
|
||||
|
||||
public $acceptDebugSessionTerminated(sessionDto: IDebugSessionDto): void {
|
||||
|
||||
this._onDidTerminateDebugSession.fire(this.getSession(sessionDto));
|
||||
this._debugSessions.delete(sessionDto.id);
|
||||
}
|
||||
|
||||
public $acceptDebugSessionActiveChanged(sessionDto: IDebugSessionDto): void {
|
||||
|
||||
this._activeDebugSession = sessionDto ? this.getSession(sessionDto) : undefined;
|
||||
this._onDidChangeActiveDebugSession.fire(this._activeDebugSession);
|
||||
}
|
||||
|
||||
public $acceptDebugSessionCustomEvent(sessionDto: IDebugSessionDto, event: any): void {
|
||||
|
||||
const ee: vscode.DebugSessionCustomEvent = {
|
||||
session: this.getSession(sessionDto),
|
||||
event: event.event,
|
||||
body: event.body
|
||||
};
|
||||
this._onDidReceiveDebugSessionCustomEvent.fire(ee);
|
||||
}
|
||||
|
||||
// private & dto helpers
|
||||
|
||||
private getAdapterDescriptor(debugConfigProvider, sessionDto: IDebugSessionDto, folderUri: UriComponents | undefined, config: vscode.DebugConfiguration): Thenable<vscode.DebugAdapterDescriptor> {
|
||||
if (debugConfigProvider) {
|
||||
if (debugConfigProvider.provideDebugAdapter) {
|
||||
const adapterExecutable = DebugAdapter.platformAdapterExecutable(this._extensionService.getAllExtensionDescriptions(), config.type);
|
||||
return asThenable(() => debugConfigProvider.provideDebugAdapter(this.getSession(sessionDto), this.getFolder(folderUri), adapterExecutable, config, CancellationToken.None));
|
||||
}
|
||||
// deprecated
|
||||
if (debugConfigProvider.debugAdapterExecutable) {
|
||||
return asThenable(() => debugConfigProvider.debugAdapterExecutable(this.getFolder(folderUri), CancellationToken.None));
|
||||
}
|
||||
}
|
||||
// fallback: use serverport or executable information from package.json
|
||||
// TODO@AW support legacy command based mechanism
|
||||
if (typeof config.debugServer === 'number') {
|
||||
return TPromise.wrap(new DebugAdapterServer(config.debugServer));
|
||||
}
|
||||
return TPromise.wrap(DebugAdapter.platformAdapterExecutable(this._extensionService.getAllExtensionDescriptions(), config.type));
|
||||
}
|
||||
|
||||
private startBreakpoints() {
|
||||
if (!this._breakpointEventsActive) {
|
||||
this._breakpointEventsActive = true;
|
||||
this._debugServiceProxy.$startBreakpointEvents();
|
||||
}
|
||||
}
|
||||
|
||||
private fireBreakpointChanges(added: vscode.Breakpoint[], removed: vscode.Breakpoint[], changed: vscode.Breakpoint[]) {
|
||||
if (added.length > 0 || removed.length > 0 || changed.length > 0) {
|
||||
this._onDidChangeBreakpoints.fire(Object.freeze({
|
||||
@@ -434,109 +561,16 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
|
||||
}
|
||||
}
|
||||
|
||||
public registerDebugConfigurationProvider(type: string, provider: vscode.DebugConfigurationProvider): vscode.Disposable {
|
||||
if (!provider) {
|
||||
return new Disposable(() => { });
|
||||
}
|
||||
|
||||
let handle = this.nextHandle();
|
||||
this._handlers.set(handle, provider);
|
||||
this._debugServiceProxy.$registerDebugConfigurationProvider(type,
|
||||
!!provider.provideDebugConfigurations,
|
||||
!!provider.resolveDebugConfiguration,
|
||||
!!provider.debugAdapterExecutable, handle);
|
||||
|
||||
return new Disposable(() => {
|
||||
this._handlers.delete(handle);
|
||||
this._debugServiceProxy.$unregisterDebugConfigurationProvider(handle);
|
||||
});
|
||||
}
|
||||
|
||||
public $provideDebugConfigurations(handle: number, folderUri: UriComponents | undefined): Thenable<vscode.DebugConfiguration[]> {
|
||||
let handler = this._handlers.get(handle);
|
||||
if (!handler) {
|
||||
return TPromise.wrapError<vscode.DebugConfiguration[]>(new Error('no handler found'));
|
||||
}
|
||||
if (!handler.provideDebugConfigurations) {
|
||||
return TPromise.wrapError<vscode.DebugConfiguration[]>(new Error('handler has no method provideDebugConfigurations'));
|
||||
}
|
||||
return asThenable(() => handler.provideDebugConfigurations(this.getFolder(folderUri), CancellationToken.None));
|
||||
}
|
||||
|
||||
public $resolveDebugConfiguration(handle: number, folderUri: UriComponents | undefined, debugConfiguration: vscode.DebugConfiguration): Thenable<vscode.DebugConfiguration> {
|
||||
let handler = this._handlers.get(handle);
|
||||
if (!handler) {
|
||||
return TPromise.wrapError<vscode.DebugConfiguration>(new Error('no handler found'));
|
||||
}
|
||||
if (!handler.resolveDebugConfiguration) {
|
||||
return TPromise.wrapError<vscode.DebugConfiguration>(new Error('handler has no method resolveDebugConfiguration'));
|
||||
}
|
||||
return asThenable(() => handler.resolveDebugConfiguration(this.getFolder(folderUri), debugConfiguration, CancellationToken.None));
|
||||
}
|
||||
|
||||
public $debugAdapterExecutable(handle: number, folderUri: UriComponents | undefined): Thenable<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 asThenable(() => handler.debugAdapterExecutable(this.getFolder(folderUri), CancellationToken.None));
|
||||
}
|
||||
|
||||
public startDebugging(folder: vscode.WorkspaceFolder | undefined, nameOrConfig: string | vscode.DebugConfiguration): Thenable<boolean> {
|
||||
return this._debugServiceProxy.$startDebugging(folder ? folder.uri : undefined, nameOrConfig);
|
||||
}
|
||||
|
||||
public $acceptDebugSessionStarted(id: DebugSessionUUID, type: string, name: string): void {
|
||||
|
||||
let debugSession = this._debugSessions.get(id);
|
||||
if (!debugSession) {
|
||||
debugSession = new ExtHostDebugSession(this._debugServiceProxy, id, type, name);
|
||||
this._debugSessions.set(id, debugSession);
|
||||
}
|
||||
this._onDidStartDebugSession.fire(debugSession);
|
||||
}
|
||||
|
||||
public $acceptDebugSessionTerminated(id: DebugSessionUUID, type: string, name: string): void {
|
||||
|
||||
let debugSession = this._debugSessions.get(id);
|
||||
if (!debugSession) {
|
||||
debugSession = new ExtHostDebugSession(this._debugServiceProxy, id, type, name);
|
||||
this._debugSessions.set(id, debugSession);
|
||||
}
|
||||
this._onDidTerminateDebugSession.fire(debugSession);
|
||||
this._debugSessions.delete(id);
|
||||
}
|
||||
|
||||
public $acceptDebugSessionActiveChanged(id: DebugSessionUUID | undefined, type?: string, name?: string): void {
|
||||
|
||||
if (id) {
|
||||
this._activeDebugSession = this._debugSessions.get(id);
|
||||
if (!this._activeDebugSession) {
|
||||
this._activeDebugSession = new ExtHostDebugSession(this._debugServiceProxy, id, type, name);
|
||||
this._debugSessions.set(id, this._activeDebugSession);
|
||||
private getSession(dto: IDebugSessionDto): ExtHostDebugSession {
|
||||
if (dto) {
|
||||
let debugSession = this._debugSessions.get(dto.id);
|
||||
if (!debugSession) {
|
||||
debugSession = new ExtHostDebugSession(this._debugServiceProxy, dto.id, dto.type, dto.name);
|
||||
this._debugSessions.set(dto.id, debugSession);
|
||||
}
|
||||
} else {
|
||||
this._activeDebugSession = undefined;
|
||||
return debugSession;
|
||||
}
|
||||
this._onDidChangeActiveDebugSession.fire(this._activeDebugSession);
|
||||
}
|
||||
|
||||
public $acceptDebugSessionCustomEvent(id: DebugSessionUUID, type: string, name: string, event: any): void {
|
||||
|
||||
let debugSession = this._debugSessions.get(id);
|
||||
if (!debugSession) {
|
||||
debugSession = new ExtHostDebugSession(this._debugServiceProxy, id, type, name);
|
||||
this._debugSessions.set(id, debugSession);
|
||||
}
|
||||
const ee: vscode.DebugSessionCustomEvent = {
|
||||
session: debugSession,
|
||||
event: event.event,
|
||||
body: event.body
|
||||
};
|
||||
this._onDidReceiveDebugSessionCustomEvent.fire(ee);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private getFolder(_folderUri: UriComponents | undefined): vscode.WorkspaceFolder | undefined {
|
||||
@@ -546,10 +580,6 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private nextHandle(): number {
|
||||
return this._handleCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostDebugSession implements vscode.DebugSession {
|
||||
@@ -557,7 +587,6 @@ export class ExtHostDebugSession implements vscode.DebugSession {
|
||||
private _debugServiceProxy: MainThreadDebugServiceShape;
|
||||
|
||||
private _id: DebugSessionUUID;
|
||||
|
||||
private _type: string;
|
||||
private _name: string;
|
||||
|
||||
|
||||
@@ -1889,6 +1889,7 @@ export class FunctionBreakpoint extends Breakpoint {
|
||||
}
|
||||
|
||||
export class DebugAdapterExecutable implements vscode.DebugAdapterExecutable {
|
||||
readonly type = 'executable';
|
||||
readonly command: string;
|
||||
readonly args: string[];
|
||||
|
||||
@@ -1898,6 +1899,15 @@ export class DebugAdapterExecutable implements vscode.DebugAdapterExecutable {
|
||||
}
|
||||
}
|
||||
|
||||
export class DebugAdapterServer implements vscode.DebugAdapterServer {
|
||||
readonly type = 'server';
|
||||
readonly port: number;
|
||||
|
||||
constructor(port: number) {
|
||||
this.port = port;
|
||||
}
|
||||
}
|
||||
|
||||
export enum LogLevel {
|
||||
Trace = 1,
|
||||
Debug = 2,
|
||||
|
||||
@@ -111,7 +111,7 @@ export interface IExpression extends IReplElement, IExpressionContainer {
|
||||
}
|
||||
|
||||
export interface IDebugger {
|
||||
createDebugAdapter(root: IWorkspaceFolder, outputService: IOutputService, debugPort?: number): TPromise<IDebugAdapter>;
|
||||
createDebugAdapter(session: IDebugSession, root: IWorkspaceFolder, config: IConfig, outputService: IOutputService): TPromise<IDebugAdapter>;
|
||||
runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments): TPromise<void>;
|
||||
getCustomTelemetryService(): TPromise<TelemetryService>;
|
||||
}
|
||||
@@ -452,15 +452,23 @@ export interface IDebugAdapter extends IDisposable {
|
||||
}
|
||||
|
||||
export interface IDebugAdapterProvider extends ITerminalLauncher {
|
||||
createDebugAdapter(debugType: string, adapterInfo: IAdapterExecutable | null, debugPort: number): IDebugAdapter;
|
||||
createDebugAdapter(session: IDebugSession, folder: IWorkspaceFolder, config: IConfig): IDebugAdapter;
|
||||
substituteVariables(folder: IWorkspaceFolder, config: IConfig): TPromise<IConfig>;
|
||||
}
|
||||
|
||||
export interface IAdapterExecutable {
|
||||
readonly command?: string;
|
||||
readonly args?: string[];
|
||||
readonly type: 'executable';
|
||||
readonly command: string;
|
||||
readonly args: string[];
|
||||
}
|
||||
|
||||
export interface IAdapterServer {
|
||||
readonly type: 'server';
|
||||
readonly port: number;
|
||||
}
|
||||
|
||||
export type IAdapterDescriptor = IAdapterExecutable | IAdapterServer;
|
||||
|
||||
export interface IPlatformSpecificAdapterContribution {
|
||||
program?: string;
|
||||
args?: string[];
|
||||
@@ -498,7 +506,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>;
|
||||
provideDebugAdapter?(session: IDebugSession, folderUri: uri | undefined, config: IConfig): TPromise<IAdapterDescriptor>;
|
||||
}
|
||||
|
||||
export interface ITerminalLauncher {
|
||||
@@ -549,10 +557,11 @@ export interface IConfigurationManager {
|
||||
unregisterDebugConfigurationProvider(handle: number): void;
|
||||
|
||||
resolveConfigurationByProviders(folderUri: uri | undefined, type: string | undefined, debugConfiguration: any): TPromise<any>;
|
||||
debugAdapterExecutable(folderUri: uri | undefined, type: string): TPromise<IAdapterExecutable | undefined>;
|
||||
provideDebugAdapter(session: IDebugSession, folderUri: uri | undefined, config: IConfig): TPromise<IAdapterDescriptor | undefined>;
|
||||
|
||||
registerDebugAdapterProvider(debugTypes: string[], debugAdapterLauncher: IDebugAdapterProvider): IDisposable;
|
||||
createDebugAdapter(debugType: string, adapterExecutable: IAdapterExecutable | null, debugPort?: number): IDebugAdapter | undefined;
|
||||
createDebugAdapter(session: IDebugSession, folder: IWorkspaceFolder, config: IConfig): IDebugAdapter;
|
||||
|
||||
substituteVariables(debugType: string, folder: IWorkspaceFolder, config: IConfig): TPromise<IConfig>;
|
||||
runInTerminal(debugType: string, args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): TPromise<void>;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,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, ICompound, IDebugConfiguration, IConfig, IGlobalConfig, IConfigurationManager, ILaunch, IAdapterExecutable, IDebugAdapterProvider, IDebugAdapter, ITerminalSettings, ITerminalLauncher } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { IDebugConfigurationProvider, ICompound, IDebugConfiguration, IConfig, IGlobalConfig, IConfigurationManager, ILaunch, IDebugAdapterProvider, IDebugAdapter, ITerminalSettings, ITerminalLauncher, IDebugSession, IAdapterDescriptor } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { Debugger } from 'vs/workbench/parts/debug/node/debugger';
|
||||
import { IEditorService, ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
@@ -119,10 +119,12 @@ 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);
|
||||
public provideDebugAdapter(session: IDebugSession, folderUri: uri | undefined, config: IConfig): TPromise<IAdapterDescriptor | undefined> {
|
||||
const providers = this.providers.filter(p => p.type === config.type && p.provideDebugAdapter);
|
||||
if (providers.length === 1) {
|
||||
return providers[0].debugAdapterExecutable(folderUri);
|
||||
return providers[0].provideDebugAdapter(session, folderUri, config);
|
||||
} else {
|
||||
// TODO@AW handle n > 1 case
|
||||
}
|
||||
return TPromise.as(undefined);
|
||||
}
|
||||
@@ -140,10 +142,10 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||
return this.debugAdapterProviders.get(type);
|
||||
}
|
||||
|
||||
public createDebugAdapter(debugType: string, adapterExecutable: IAdapterExecutable, debugPort: number): IDebugAdapter | undefined {
|
||||
let dap = this.getDebugAdapterProvider(debugType);
|
||||
public createDebugAdapter(session: IDebugSession, folder: IWorkspaceFolder, config: IConfig): IDebugAdapter {
|
||||
let dap = this.getDebugAdapterProvider(config.type);
|
||||
if (dap) {
|
||||
return dap.createDebugAdapter(debugType, adapterExecutable, debugPort);
|
||||
return dap.createDebugAdapter(session, folder, config);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ export class DebugSession implements IDebugSession {
|
||||
|
||||
return dbgr.getCustomTelemetryService().then(customTelemetryService => {
|
||||
|
||||
return dbgr.createDebugAdapter(this.root, this.outputService, this._configuration.resolved.debugServer).then(debugAdapter => {
|
||||
return dbgr.createDebugAdapter(this, this.root, this._configuration.resolved, this.outputService).then(debugAdapter => {
|
||||
|
||||
this._raw = new RawDebugSession(debugAdapter, dbgr, this.telemetryService, customTelemetryService);
|
||||
|
||||
|
||||
@@ -294,12 +294,8 @@ export class DebugAdapter extends StreamDebugAdapter {
|
||||
|
||||
private serverProcess: cp.ChildProcess;
|
||||
|
||||
constructor(private debugType: string, private adapterExecutable: IAdapterExecutable | null, extensionDescriptions: IExtensionDescription[], private outputService?: IOutputService) {
|
||||
constructor(private debugType: string, private adapterExecutable: IAdapterExecutable, private outputService?: IOutputService) {
|
||||
super();
|
||||
|
||||
if (!this.adapterExecutable) {
|
||||
this.adapterExecutable = DebugAdapter.platformAdapterExecutable(extensionDescriptions, this.debugType);
|
||||
}
|
||||
}
|
||||
|
||||
startSession(): TPromise<void> {
|
||||
@@ -492,11 +488,13 @@ export class DebugAdapter extends StreamDebugAdapter {
|
||||
|
||||
if (runtime) {
|
||||
return {
|
||||
type: 'executable',
|
||||
command: runtime,
|
||||
args: (runtimeArgs || []).concat([program]).concat(args || [])
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
type: 'executable',
|
||||
command: program,
|
||||
args: args || []
|
||||
};
|
||||
|
||||
@@ -11,7 +11,7 @@ import * as objects from 'vs/base/common/objects';
|
||||
import { TelemetryAppenderClient } from 'vs/platform/telemetry/node/telemetryIpc';
|
||||
import { IJSONSchema, IJSONSchemaSnippet } from 'vs/base/common/jsonSchema';
|
||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { IConfig, IDebuggerContribution, IAdapterExecutable, INTERNAL_CONSOLE_OPTIONS_SCHEMA, IConfigurationManager, IDebugAdapter, IDebugConfiguration, ITerminalSettings, IDebugger } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { IConfig, IDebuggerContribution, IAdapterExecutable, INTERNAL_CONSOLE_OPTIONS_SCHEMA, IConfigurationManager, IDebugAdapter, IDebugConfiguration, ITerminalSettings, IDebugger, IDebugSession, IAdapterDescriptor, IAdapterServer } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
@@ -39,36 +39,43 @@ export class Debugger implements IDebugger {
|
||||
|
||||
public hasConfigurationProvider = false;
|
||||
|
||||
public createDebugAdapter(root: IWorkspaceFolder, outputService: IOutputService, debugPort?: number): TPromise<IDebugAdapter> {
|
||||
return this.getAdapterExecutable(root).then(adapterExecutable => {
|
||||
if (this.inEH()) {
|
||||
return this.configurationManager.createDebugAdapter(this.type, adapterExecutable, debugPort);
|
||||
} else {
|
||||
if (debugPort) {
|
||||
return new SocketDebugAdapter(debugPort);
|
||||
} else {
|
||||
return new DebugAdapter(this.type, adapterExecutable, this.mergedExtensionDescriptions, outputService);
|
||||
public createDebugAdapter(session: IDebugSession, root: IWorkspaceFolder, config: IConfig, outputService: IOutputService): TPromise<IDebugAdapter> {
|
||||
if (this.inEH()) {
|
||||
return TPromise.as(this.configurationManager.createDebugAdapter(session, root, config));
|
||||
} else {
|
||||
return this.getAdapterDescriptor(session, root, config).then(adapterDescriptor => {
|
||||
switch (adapterDescriptor.type) {
|
||||
case 'server':
|
||||
return new SocketDebugAdapter(adapterDescriptor.port);
|
||||
case 'executable':
|
||||
return new DebugAdapter(this.type, adapterDescriptor, outputService);
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public getAdapterExecutable(root: IWorkspaceFolder): TPromise<IAdapterExecutable | null> {
|
||||
private getAdapterDescriptor(session: IDebugSession, root: IWorkspaceFolder, config: IConfig): TPromise<IAdapterDescriptor> {
|
||||
|
||||
// first try to get an executable from DebugConfigurationProvider
|
||||
return this.configurationManager.debugAdapterExecutable(root ? root.uri : undefined, this.type).then(adapterExecutable => {
|
||||
// try deprecated command based extension API to receive an executable
|
||||
if (this.debuggerContribution.adapterExecutableCommand) {
|
||||
const adapterExecutable = this.commandService.executeCommand<IAdapterExecutable>(this.debuggerContribution.adapterExecutableCommand, root ? root.uri.toString() : undefined);
|
||||
return TPromise.wrap(adapterExecutable);
|
||||
}
|
||||
|
||||
if (adapterExecutable) {
|
||||
return adapterExecutable;
|
||||
return this.configurationManager.provideDebugAdapter(session, root ? root.uri : undefined, config).then(adapter => {
|
||||
if (adapter) {
|
||||
return adapter;
|
||||
}
|
||||
|
||||
// try deprecated command based extension API to receive an executable
|
||||
if (this.debuggerContribution.adapterExecutableCommand) {
|
||||
return this.commandService.executeCommand<IAdapterExecutable>(this.debuggerContribution.adapterExecutableCommand, root ? root.uri.toString() : undefined);
|
||||
if (typeof config.debugServer === 'number') {
|
||||
return <IAdapterServer>{
|
||||
type: 'server',
|
||||
port: config.debugServer
|
||||
};
|
||||
}
|
||||
|
||||
// give up and let DebugAdapter determine executable based on package.json contribution
|
||||
return TPromise.as(null);
|
||||
// fallback: use information from package.json
|
||||
return DebugAdapter.platformAdapterExecutable(this.mergedExtensionDescriptions, this.type);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import * as assert from 'assert';
|
||||
import * as paths from 'vs/base/common/paths';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { IAdapterExecutable, IConfigurationManager } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { IAdapterExecutable, IConfigurationManager, IConfig, IDebugSession } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { Debugger } from 'vs/workbench/parts/debug/node/debugger';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
@@ -117,7 +117,7 @@ suite('Debug - Debugger', () => {
|
||||
|
||||
|
||||
const configurationManager = <IConfigurationManager>{
|
||||
debugAdapterExecutable(folderUri: URI | undefined, type: string): TPromise<IAdapterExecutable | undefined> {
|
||||
provideDebugAdapter(session: IDebugSession, folderUri: URI | undefined, config: IConfig): TPromise<IAdapterExecutable | undefined> {
|
||||
return TPromise.as(undefined);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user