diff --git a/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts b/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts index 6a3d4c18a57..af2d76abc49 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts @@ -61,9 +61,9 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb this._toDispose.push(this.debugService.getConfigurationManager().registerDebugAdapterProvider(debugTypes, this)); } - createDebugAdapter(debugType: string, adapterInfo): IDebugAdapter { + createDebugAdapter(debugType: string, adapterInfo, debugPort: number): IDebugAdapter { const handle = this._debugAdaptersHandleCounter++; - const da = new ExtensionHostDebugAdapter(handle, this._proxy, debugType, adapterInfo); + const da = new ExtensionHostDebugAdapter(handle, this._proxy, debugType, adapterInfo, debugPort); this._debugAdapters.set(handle, da); return da; } @@ -262,7 +262,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) { + constructor(private _handle: number, private _proxy: ExtHostDebugServiceShape, private _debugType: string, private _adapterExecutable: IAdapterExecutable | null, private _debugPort: number) { super(); } @@ -275,7 +275,7 @@ class ExtensionHostDebugAdapter extends AbstractDebugAdapter { } public startSession(): TPromise { - return this._proxy.$startDASession(this._handle, this._debugType, this._adapterExecutable); + return this._proxy.$startDASession(this._handle, this._debugType, this._adapterExecutable, this._debugPort); } public sendMessage(message: DebugProtocol.ProtocolMessage): void { diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index b2404b7eb2c..56897f732ba 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -821,7 +821,7 @@ export interface ISourceMultiBreakpointDto { export interface ExtHostDebugServiceShape { $substituteVariables(folder: UriComponents | undefined, config: IConfig): TPromise; $runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): TPromise; - $startDASession(handle: number, debugType: string, adapterExecutableInfo: IAdapterExecutable | null): TPromise; + $startDASession(handle: number, debugType: string, adapterExecutableInfo: IAdapterExecutable | null, debugPort: number): TPromise; $stopDASession(handle: number): TPromise; $sendDAMessage(handle: number, message: DebugProtocol.ProtocolMessage): TPromise; $resolveDebugConfiguration(handle: number, folder: UriComponents | undefined, debugConfiguration: IConfig): TPromise; diff --git a/src/vs/workbench/api/node/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts index 7b27765e1c8..2ddd689adee 100644 --- a/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -17,11 +17,11 @@ import { import * as vscode from 'vscode'; import { Disposable, Position, Location, SourceBreakpoint, FunctionBreakpoint } from 'vs/workbench/api/node/extHostTypes'; import { generateUuid } from 'vs/base/common/uuid'; -import { DebugAdapter } from 'vs/workbench/parts/debug/node/debugAdapter'; +import { DebugAdapter, StreamDebugAdapter, 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 } from 'vs/workbench/parts/debug/common/debug'; +import { IAdapterExecutable, ITerminalSettings, IDebuggerContribution, IConfig, IDebugAdapter } from 'vs/workbench/parts/debug/common/debug'; import { getTerminalLauncher } from 'vs/workbench/parts/debug/node/terminals'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { VariableResolver } from 'vs/workbench/services/configurationResolver/node/variableResolver'; @@ -62,7 +62,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { private readonly _onDidChangeBreakpoints: Emitter; - private _debugAdapters: Map; + private _debugAdapters: Map; private _variableResolver: IConfigurationResolverService; @@ -133,22 +133,41 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { return asWinJsPromise(token => DebugAdapter.substituteVariables(folder, config, this._variableResolver)); } - public $startDASession(handle: number, debugType: string, adpaterExecutable: IAdapterExecutable | null): TPromise { + public $startDASession(handle: number, debugType: string, adpaterExecutable: IAdapterExecutable | null, debugPort: number): TPromise { const mythis = this; - const da = new class extends DebugAdapter { + let da: StreamDebugAdapter = null; - // DA -> VS Code - public acceptMessage(message: DebugProtocol.ProtocolMessage) { - convertToVSCPaths(message, source => { - if (paths.isAbsolute(source.path)) { - (source).path = URI.file(source.path); - } - }); - mythis._debugServiceProxy.$acceptDAMessage(handle, message); - } + if (debugPort > 0) { + da = new class extends SocketDebugAdapter { - }(debugType, adpaterExecutable, this._extensionService.getAllExtensionDescriptions()); + // DA -> VS Code + public acceptMessage(message: DebugProtocol.ProtocolMessage) { + convertToVSCPaths(message, source => { + if (paths.isAbsolute(source.path)) { + (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)) { + (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)); diff --git a/src/vs/workbench/parts/debug/common/debug.ts b/src/vs/workbench/parts/debug/common/debug.ts index bc09f853ab7..e15c93101b3 100644 --- a/src/vs/workbench/parts/debug/common/debug.ts +++ b/src/vs/workbench/parts/debug/common/debug.ts @@ -406,7 +406,7 @@ export interface IDebugAdapter extends IDisposable { } export interface IDebugAdapterProvider extends ITerminalLauncher { - createDebugAdapter(debugType: string, adapterInfo: IAdapterExecutable | null): IDebugAdapter; + createDebugAdapter(debugType: string, adapterInfo: IAdapterExecutable | null, debugPort: number): IDebugAdapter; substituteVariables(folder: IWorkspaceFolder, config: IConfig): TPromise; } @@ -506,7 +506,7 @@ export interface IConfigurationManager { debugAdapterExecutable(folderUri: uri | undefined, type: string): TPromise; registerDebugAdapterProvider(debugTypes: string[], debugAdapterLauncher: IDebugAdapterProvider): IDisposable; - createDebugAdapter(debugType: string, adapterExecutable: IAdapterExecutable | null): IDebugAdapter | undefined; + createDebugAdapter(debugType: string, adapterExecutable: IAdapterExecutable | null, debugPort?: number): IDebugAdapter | undefined; substituteVariables(debugType: string, folder: IWorkspaceFolder, config: IConfig): TPromise; runInTerminal(debugType: string, args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): TPromise; } diff --git a/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts b/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts index aa81696efb5..0c76ad152f1 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts @@ -140,10 +140,10 @@ export class ConfigurationManager implements IConfigurationManager { return this.debugAdapterProviders.get(type); } - public createDebugAdapter(debugType: string, adapterExecutable: IAdapterExecutable): IDebugAdapter | undefined { + public createDebugAdapter(debugType: string, adapterExecutable: IAdapterExecutable, debugPort: number): IDebugAdapter | undefined { let dap = this.getDebugAdapterProvider(debugType); if (dap) { - return dap.createDebugAdapter(debugType, adapterExecutable); + return dap.createDebugAdapter(debugType, adapterExecutable, debugPort); } return undefined; } diff --git a/src/vs/workbench/parts/debug/electron-browser/rawDebugSession.ts b/src/vs/workbench/parts/debug/electron-browser/rawDebugSession.ts index 78ce3ff55de..010fe58f102 100644 --- a/src/vs/workbench/parts/debug/electron-browser/rawDebugSession.ts +++ b/src/vs/workbench/parts/debug/electron-browser/rawDebugSession.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import * as net from 'net'; import { Event, Emitter } from 'vs/base/common/event'; import * as objects from 'vs/base/common/objects'; import { Action } from 'vs/base/common/actions'; @@ -16,8 +15,8 @@ import { Debugger } from 'vs/workbench/parts/debug/node/debugger'; import { IOutputService } from 'vs/workbench/parts/output/common/output'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { StreamDebugAdapter } from 'vs/workbench/parts/debug/node/debugAdapter'; import { formatPII } from 'vs/workbench/parts/debug/common/debugUtils'; +import { SocketDebugAdapter } from 'vs/workbench/parts/debug/node/debugAdapter'; export interface SessionExitedEvent extends debug.DebugEvent { @@ -34,36 +33,6 @@ export interface SessionTerminatedEvent extends debug.DebugEvent { }; } -export class SocketDebugAdapter extends StreamDebugAdapter { - - private socket: net.Socket; - - constructor(private host: string, private port: number) { - super(); - } - - startSession(): TPromise { - return new TPromise((c, e) => { - this.socket = net.createConnection(this.port, this.host, () => { - this.connect(this.socket, this.socket); - c(null); - }); - this.socket.on('error', (err: any) => { - e(err); - }); - this.socket.on('close', () => this._onExit.fire(0)); - }); - } - - stopSession(): TPromise { - if (this.socket !== null) { - this.socket.end(); - this.socket = undefined; - } - return void 0; - } -} - export class RawDebugSession implements debug.IRawSession { private debugAdapter: debug.IDebugAdapter; @@ -186,11 +155,7 @@ export class RawDebugSession implements debug.IRawSession { private startSession(): TPromise { - const debugAdapterP = this.debugServerPort - ? TPromise.as(new SocketDebugAdapter('127.0.0.1', this.debugServerPort)) - : this._debugger.createDebugAdapter(this.root, this.outputService); - - return debugAdapterP.then(debugAdapter => { + return this._debugger.createDebugAdapter(this.root, this.outputService, this.debugServerPort).then(debugAdapter => { this.debugAdapter = debugAdapter; diff --git a/src/vs/workbench/parts/debug/node/debugAdapter.ts b/src/vs/workbench/parts/debug/node/debugAdapter.ts index aa840a1f173..befbb0fd4e8 100644 --- a/src/vs/workbench/parts/debug/node/debugAdapter.ts +++ b/src/vs/workbench/parts/debug/node/debugAdapter.ts @@ -7,6 +7,7 @@ import * as fs from 'fs'; import * as cp from 'child_process'; import * as stream from 'stream'; import * as nls from 'vs/nls'; +import * as net from 'net'; import * as paths from 'vs/base/common/paths'; import * as strings from 'vs/base/common/strings'; import * as objects from 'vs/base/common/objects'; @@ -215,6 +216,39 @@ export abstract class StreamDebugAdapter extends AbstractDebugAdapter { } } +/** + * An implementation that connects to a debug adapter via a socket. +*/ +export class SocketDebugAdapter extends StreamDebugAdapter { + + private socket: net.Socket; + + constructor(private port: number, private host = '127.0.0.1') { + super(); + } + + startSession(): TPromise { + return new TPromise((c, e) => { + this.socket = net.createConnection(this.port, this.host, () => { + this.connect(this.socket, this.socket); + c(null); + }); + this.socket.on('error', (err: any) => { + e(err); + }); + this.socket.on('close', () => this._onExit.fire(0)); + }); + } + + stopSession(): TPromise { + if (this.socket !== null) { + this.socket.end(); + this.socket = undefined; + } + return void 0; + } +} + /** * An implementation that launches the debug adapter as a separate process and communicates via stdin/stdout. */ diff --git a/src/vs/workbench/parts/debug/node/debugger.ts b/src/vs/workbench/parts/debug/node/debugger.ts index 1e391eb0f40..419ec9d441c 100644 --- a/src/vs/workbench/parts/debug/node/debugger.ts +++ b/src/vs/workbench/parts/debug/node/debugger.ts @@ -16,7 +16,7 @@ import { IExtensionDescription } from 'vs/workbench/services/extensions/common/e import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IOutputService } from 'vs/workbench/parts/output/common/output'; -import { DebugAdapter } from 'vs/workbench/parts/debug/node/debugAdapter'; +import { DebugAdapter, SocketDebugAdapter } from 'vs/workbench/parts/debug/node/debugAdapter'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; import uri from 'vs/base/common/uri'; @@ -38,13 +38,17 @@ export class Debugger { public hasConfigurationProvider = false; - public createDebugAdapter(root: IWorkspaceFolder, outputService: IOutputService): TPromise { + public createDebugAdapter(root: IWorkspaceFolder, outputService: IOutputService, debugPort?: number): TPromise { return this.getAdapterExecutable(root).then(adapterExecutable => { const debugConfigs = this.configurationService.getValue('debug'); if (debugConfigs.extensionHostDebugAdapter) { - return this.configurationManager.createDebugAdapter(this.type, adapterExecutable); + return this.configurationManager.createDebugAdapter(this.type, adapterExecutable, debugPort); } else { - return new DebugAdapter(this.type, adapterExecutable, this.mergedExtensionDescriptions, outputService); + if (debugPort) { + return new SocketDebugAdapter(debugPort); + } else { + return new DebugAdapter(this.type, adapterExecutable, this.mergedExtensionDescriptions, outputService); + } } }); }