diff --git a/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts b/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts index f67391f2c07..4c1f392c1b8 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts @@ -6,7 +6,7 @@ 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, ISession } from 'vs/workbench/parts/debug/common/debug'; +import { IDebugService, IConfig, IDebugConfigurationProvider, IBreakpoint, IFunctionBreakpoint, IBreakpointData, IAdapterExecutable, ITerminalSettings, IDebugAdapter, IDebugAdapterProvider } from 'vs/workbench/parts/debug/common/debug'; import { TPromise } from 'vs/base/common/winjs.base'; import { ExtHostContext, ExtHostDebugServiceShape, MainThreadDebugServiceShape, DebugSessionUUID, MainContext, @@ -28,7 +28,6 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb private _breakpointEventsActive: boolean; private _debugAdapters: Map; private _debugAdaptersHandleCounter = 1; - private _sessions: Map; constructor( extHostContext: IExtHostContext, @@ -39,19 +38,12 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb this._toDispose.push(debugService.onDidNewSession(session => { this._proxy.$acceptDebugSessionStarted(session.getId(), session.configuration.type, session.getName(false)); })); - this._sessions = new Map(); + // 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._sessions.set(session.getId(), session); - // Need to start listening early to new session events because a custom event can come while a session is initialising - this._toDispose.push(session.onDidCustomEvent(event => { - if (event && event.sessionId) { - this._proxy.$acceptDebugSessionCustomEvent(event.sessionId, session.configuration.type, session.configuration.name, event); - } - })); + this._toDispose.push(session.onDidCustomEvent(event => this._proxy.$acceptDebugSessionCustomEvent(session.getId(), session.configuration.type, session.configuration.name, event))); })); this._toDispose.push(debugService.onDidEndSession(session => { this._proxy.$acceptDebugSessionTerminated(session.getId(), session.configuration.type, session.getName(false)); - this._sessions.delete(session.getId()); })); this._toDispose.push(debugService.getViewModel().onDidFocusSession(proc => { if (proc) { @@ -226,7 +218,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb } public $customDebugAdapterRequest(sessionId: DebugSessionUUID, request: string, args: any): TPromise { - const session = this._sessions.get(sessionId); + const session = this.debugService.getSession(sessionId); if (session) { return session.raw.custom(request, args).then(response => { if (response && response.success) { diff --git a/src/vs/workbench/parts/debug/common/debug.ts b/src/vs/workbench/parts/debug/common/debug.ts index bd04f03fc1f..829775b769f 100644 --- a/src/vs/workbench/parts/debug/common/debug.ts +++ b/src/vs/workbench/parts/debug/common/debug.ts @@ -162,8 +162,11 @@ export interface ISession extends ITreeElement, IDisposable { /** * Allows to register on custom DAP events. */ - onDidCustomEvent: Event; + onDidCustomEvent: Event; + /** + * Allows to register on DA events. + */ onDidExitAdapter: Event; } @@ -582,10 +585,6 @@ export interface ILaunch { export const IDebugService = createDecorator(DEBUG_SERVICE_ID); -export interface DebugEvent extends DebugProtocol.Event { - sessionId?: string; -} - export interface LoadedSourceEvent { reason: string; source: Source; @@ -737,6 +736,11 @@ export interface IDebugService { */ sourceIsNotAvailable(uri: uri): void; + /** + * returns Session with the given ID (or undefined if ID is not found) + */ + getSession(sessionId: string): ISession; + /** * Gets the current debug model. */ diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index c6b673c98d8..04433ed21d1 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -6,7 +6,6 @@ import * as nls from 'vs/nls'; import { Event, Emitter } from 'vs/base/common/event'; import * as resources from 'vs/base/common/resources'; -import { generateUuid } from 'vs/base/common/uuid'; import { URI as uri } from 'vs/base/common/uri'; import { first, distinct } from 'vs/base/common/arrays'; import { isObject, isUndefinedOrNull } from 'vs/base/common/types'; @@ -129,7 +128,7 @@ export class DebugService implements IDebugService { this.lifecycleService.onShutdown(this.dispose, this); this.toDispose.push(this.broadcastService.onBroadcast(broadcast => { - const session = this.allSessions.get(broadcast.payload.debugId); + const session = this.getSession(broadcast.payload.debugId); if (session) { switch (broadcast.channel) { @@ -160,6 +159,10 @@ export class DebugService implements IDebugService { })); } + getSession(sessionId: string): ISession { + return this.allSessions.get(sessionId); + } + getModel(): IModel { return this.model; } @@ -236,12 +239,15 @@ export class DebugService implements IDebugService { //---- life cycle management + /** + * main entry point + */ startDebugging(launch: ILaunch, configOrName?: IConfig | string, noDebug = false, unresolvedConfiguration?: IConfig, ): TPromise { - const sessionId = generateUuid(); // make sure to save all files and that the configuration is up to date return this.extensionService.activateByEvent('onDebug').then(() => this.textFileService.saveAll().then(() => this.configurationService.reloadConfiguration(launch ? launch.workspace : undefined).then(() => this.extensionService.whenInstalledExtensionsRegistered().then(() => { + if (this.model.getSessions().length === 0) { this.removeReplExpressions(); this.allSessions.clear(); @@ -328,7 +334,7 @@ export class DebugService implements IDebugService { this.configurationManager.resolveConfigurationByProviders(launch && launch.workspace ? launch.workspace.uri : undefined, type, config).then(config => { // a falsy config indicates an aborted launch if (config && config.type) { - return this.createSession(launch, config, unresolvedConfiguration, sessionId); + return this.createSession(launch, config, unresolvedConfiguration); } if (launch && type) { @@ -342,7 +348,7 @@ export class DebugService implements IDebugService { ))); } - private createSession(launch: ILaunch, config: IConfig, unresolvedConfig: IConfig, sessionId: string): TPromise { + private createSession(launch: ILaunch, config: IConfig, unresolvedConfig: IConfig): TPromise { this.startInitializing(); @@ -369,12 +375,12 @@ export class DebugService implements IDebugService { } const workspace = launch ? launch.workspace : undefined; - return this.runTask(sessionId, workspace, resolvedConfig.preLaunchTask, resolvedConfig, unresolvedConfig).then(success => { + return this.runTask(workspace, resolvedConfig.preLaunchTask, resolvedConfig, unresolvedConfig).then(success => { if (!success) { return undefined; } - return this.doCreateSession(workspace, { resolved: resolvedConfig, unresolved: unresolvedConfig }, sessionId); + return this.doCreateSession(workspace, { resolved: resolvedConfig, unresolved: unresolvedConfig }); }); }, err => { if (err && err.message) { @@ -395,78 +401,88 @@ export class DebugService implements IDebugService { } private attachExtensionHost(session: Session, port: number): TPromise { + session.configuration.request = 'attach'; session.configuration.port = port; const dbgr = this.configurationManager.getDebugger(session.configuration.type); + return session.initialize(dbgr).then(() => { - (session.raw).attach(session.configuration); - this.focusStackFrame(undefined, undefined, session); + (session.raw).attach(session.configuration).then(result => { + this.focusStackFrame(undefined, undefined, session); + }); }); } - private doCreateSession(root: IWorkspaceFolder, configuration: { resolved: IConfig, unresolved: IConfig }, sessionId: string): TPromise { + private doCreateSession(root: IWorkspaceFolder, configuration: { resolved: IConfig, unresolved: IConfig }): TPromise { + + const session = this.instantiationService.createInstance(Session, configuration, root, this.model); + this.allSessions.set(session.getId(), session); + + this._onWillNewSession.fire(session); const resolved = configuration.resolved; - resolved.__sessionId = sessionId; - + resolved.__sessionId = session.getId(); const dbgr = this.configurationManager.getDebugger(resolved.type); - const session = this.instantiationService.createInstance(Session, sessionId, configuration, root, this.model); - this._onWillNewSession.fire(session); - this.allSessions.set(sessionId, session); + return session.initialize(dbgr).then(() => { + this.registerSessionListeners(session); + const raw = session.raw; - return (resolved.request === 'attach' ? raw.attach(resolved) : raw.launch(resolved)) - .then((result: DebugProtocol.Response) => { - if (raw.disconnected) { - return TPromise.as(null); - } - this.focusStackFrame(undefined, undefined, session); - this._onDidNewSession.fire(session); - const internalConsoleOptions = resolved.internalConsoleOptions || this.configurationService.getValue('debug').internalConsoleOptions; - if (internalConsoleOptions === 'openOnSessionStart' || (this.viewModel.firstSessionStart && internalConsoleOptions === 'openOnFirstSessionStart')) { - this.panelService.openPanel(REPL_ID, false); - } + return (resolved.request === 'attach' ? raw.attach(resolved) : raw.launch(resolved)).then(result => { - const openDebug = this.configurationService.getValue('debug').openDebug; - // Open debug viewlet based on the visibility of the side bar and openDebug setting - if (openDebug === 'openOnSessionStart' || (openDebug === 'openOnFirstSessionStart' && this.viewModel.firstSessionStart)) { - this.viewletService.openViewlet(VIEWLET_ID); - } - this.viewModel.firstSessionStart = false; + if (raw.disconnected) { + return TPromise.as(null); + } - this.debugType.set(resolved.type); - if (this.model.getSessions().length > 1) { - this.viewModel.setMultiSessionView(true); - } + this.focusStackFrame(undefined, undefined, session); - return this.telemetryDebugSessionStart(root, resolved.type, dbgr.extensionDescription); + this._onDidNewSession.fire(session); - }).then(() => session, (error: Error | string) => { - if (session) { - session.dispose(); - } + const internalConsoleOptions = resolved.internalConsoleOptions || this.configurationService.getValue('debug').internalConsoleOptions; + if (internalConsoleOptions === 'openOnSessionStart' || (this.viewModel.firstSessionStart && internalConsoleOptions === 'openOnFirstSessionStart')) { + this.panelService.openPanel(REPL_ID, false); + } - if (errors.isPromiseCanceledError(error)) { - // Do not show 'canceled' error messages to the user #7906 - return TPromise.as(null); - } + const openDebug = this.configurationService.getValue('debug').openDebug; + // Open debug viewlet based on the visibility of the side bar and openDebug setting + if (openDebug === 'openOnSessionStart' || (openDebug === 'openOnFirstSessionStart' && this.viewModel.firstSessionStart)) { + this.viewletService.openViewlet(VIEWLET_ID); + } + this.viewModel.firstSessionStart = false; - // Show the repl if some error got logged there #5870 - if (this.model.getReplElements().length > 0) { - this.panelService.openPanel(REPL_ID, false); - } + this.debugType.set(resolved.type); + if (this.model.getSessions().length > 1) { + this.viewModel.setMultiSessionView(true); + } - if (resolved && resolved.request === 'attach' && resolved.__autoAttach) { - // ignore attach timeouts in auto attach mode - } else { - const errorMessage = error instanceof Error ? error.message : error; - this.telemetryDebugMisconfiguration(resolved ? resolved.type : undefined, errorMessage); - this.showError(errorMessage, errors.isErrorWithActions(error) ? error.actions : []); - } - return undefined; - }); + return this.telemetryDebugSessionStart(root, resolved.type, dbgr.extensionDescription); + + }).then(() => session, (error: Error | string) => { + if (session) { + session.dispose(); + } + + if (errors.isPromiseCanceledError(error)) { + // Do not show 'canceled' error messages to the user #7906 + return TPromise.as(null); + } + + // Show the repl if some error got logged there #5870 + if (this.model.getReplElements().length > 0) { + this.panelService.openPanel(REPL_ID, false); + } + + if (resolved && resolved.request === 'attach' && resolved.__autoAttach) { + // ignore attach timeouts in auto attach mode + } else { + const errorMessage = error instanceof Error ? error.message : error; + this.telemetryDebugMisconfiguration(resolved ? resolved.type : undefined, errorMessage); + this.showError(errorMessage, errors.isErrorWithActions(error) ? error.actions : []); + } + return undefined; + }); }).then(undefined, err => { if (session) { @@ -499,7 +515,7 @@ export class DebugService implements IDebugService { this.telemetryDebugSessionStop(session); if (session.configuration.postDebugTask) { - this.doRunTask(session.getId(), session.root, session.configuration.postDebugTask).then(undefined, err => + this.doRunTask(session.root, session.configuration.postDebugTask).then(undefined, err => this.notificationService.error(err) ); } @@ -527,8 +543,8 @@ export class DebugService implements IDebugService { return this.textFileService.saveAll().then(() => { const unresolvedConfiguration = (session).unresolvedConfiguration; if (session.capabilities.supportsRestartRequest) { - return this.runTask(session.getId(), session.root, session.configuration.postDebugTask, session.configuration, unresolvedConfiguration) - .then(success => success ? this.runTask(session.getId(), session.root, session.configuration.preLaunchTask, session.configuration, unresolvedConfiguration) + return this.runTask(session.root, session.configuration.postDebugTask, session.configuration, unresolvedConfiguration) + .then(success => success ? this.runTask(session.root, session.configuration.preLaunchTask, session.configuration, unresolvedConfiguration) .then(success => success ? session.raw.custom('restart', null) : undefined) : TPromise.as(undefined)); } @@ -580,6 +596,7 @@ export class DebugService implements IDebugService { } stopSession(session: ISession): TPromise { + if (session) { return session.raw.terminate(); } @@ -629,12 +646,13 @@ export class DebugService implements IDebugService { //---- task management - private runTask(sessionId: string, root: IWorkspaceFolder, taskId: string | TaskIdentifier, config: IConfig, unresolvedConfig: IConfig): TPromise { + private runTask(root: IWorkspaceFolder, taskId: string | TaskIdentifier, config: IConfig, unresolvedConfig: IConfig): TPromise { + const debugAnywayAction = new Action('debug.debugAnyway', nls.localize('debugAnyway', "Debug Anyway"), undefined, true, () => { - return this.doCreateSession(root, { resolved: config, unresolved: unresolvedConfig }, sessionId); + return this.doCreateSession(root, { resolved: config, unresolved: unresolvedConfig }); }); - return this.doRunTask(sessionId, root, taskId).then((taskSummary: ITaskSummary) => { + return this.doRunTask(root, taskId).then((taskSummary: ITaskSummary) => { const errorCount = config.preLaunchTask ? this.markerService.getStatistics().errors : 0; const successExitCode = taskSummary && taskSummary.exitCode === 0; const failureExitCode = taskSummary && taskSummary.exitCode !== undefined && taskSummary.exitCode !== 0; @@ -656,7 +674,7 @@ export class DebugService implements IDebugService { }); } - private doRunTask(sessionId: string, root: IWorkspaceFolder, taskId: string | TaskIdentifier): TPromise { + private doRunTask(root: IWorkspaceFolder, taskId: string | TaskIdentifier): TPromise { if (!taskId || this.skipRunningTask) { this.skipRunningTask = false; return TPromise.as(null); diff --git a/src/vs/workbench/parts/debug/electron-browser/debugSession.ts b/src/vs/workbench/parts/debug/electron-browser/debugSession.ts index d1dde41de6a..b6d1abcc442 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugSession.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugSession.ts @@ -13,7 +13,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { ISuggestion } from 'vs/editor/common/modes'; import { Position } from 'vs/editor/common/core/position'; import * as aria from 'vs/base/browser/ui/aria/aria'; -import { ISession, IConfig, IThread, IRawModelUpdate, IDebugService, IRawStoppedDetails, State, IRawSession, LoadedSourceEvent, DebugEvent } from 'vs/workbench/parts/debug/common/debug'; +import { ISession, IConfig, IThread, IRawModelUpdate, IDebugService, IRawStoppedDetails, State, IRawSession, LoadedSourceEvent } from 'vs/workbench/parts/debug/common/debug'; import { Source } from 'vs/workbench/parts/debug/common/debugSource'; import { mixin } from 'vs/base/common/objects'; import { Thread, ExpressionContainer, Model } from 'vs/workbench/parts/debug/common/debugModel'; @@ -30,6 +30,8 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; export class Session implements ISession { + private id: string; + private sources = new Map(); private threads = new Map(); private rawListeners: IDisposable[] = []; @@ -37,12 +39,11 @@ export class Session implements ISession { private _raw: RawDebugSession; private _state: State; private readonly _onDidLoadedSource = new Emitter(); - private readonly _onDidCustomEvent = new Emitter(); + private readonly _onDidCustomEvent = new Emitter(); private readonly _onDidChangeState = new Emitter(); private readonly _onDidExitAdapter = new Emitter(); constructor( - private id: string, private _configuration: { resolved: IConfig, unresolved: IConfig }, public root: IWorkspaceFolder, private model: Model, @@ -51,9 +52,14 @@ export class Session implements ISession { @IDebugService private debugService: IDebugService, @ITelemetryService private telemetryService: ITelemetryService, ) { + this.id = generateUuid(); this.state = State.Initializing; } + getId(): string { + return this.id; + } + get raw(): IRawSession { return this._raw; } @@ -87,10 +93,6 @@ export class Session implements ISession { return this._onDidChangeState.event; } - getId(): string { - return this.id; - } - getSourceForUri(modelUri: uri): Source { return this.sources.get(modelUri.toString()); } @@ -133,7 +135,7 @@ export class Session implements ISession { return this._onDidLoadedSource.event; } - get onDidCustomEvent(): Event { + get onDidCustomEvent(): Event { return this._onDidCustomEvent.event; } @@ -233,7 +235,7 @@ export class Session implements ISession { } return dbgr.getCustomTelemetryService().then(customTelemetryService => { - this._raw = this.instantiationService.createInstance(RawDebugSession, this.id, this._configuration.resolved.debugServer, dbgr, customTelemetryService, this.root); + this._raw = this.instantiationService.createInstance(RawDebugSession, this._configuration.resolved.debugServer, dbgr, customTelemetryService, this.root); this.registerListeners(); return this._raw.initialize({ diff --git a/src/vs/workbench/parts/debug/electron-browser/rawDebugSession.ts b/src/vs/workbench/parts/debug/electron-browser/rawDebugSession.ts index 62890046945..fadd66ca9c9 100644 --- a/src/vs/workbench/parts/debug/electron-browser/rawDebugSession.ts +++ b/src/vs/workbench/parts/debug/electron-browser/rawDebugSession.ts @@ -16,54 +16,41 @@ import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { formatPII } from 'vs/workbench/parts/debug/common/debugUtils'; import { SocketDebugAdapter } from 'vs/workbench/parts/debug/node/debugAdapter'; -import { DebugEvent, IRawSession, IDebugAdapter } from 'vs/workbench/parts/debug/common/debug'; +import { IRawSession, IDebugAdapter } from 'vs/workbench/parts/debug/common/debug'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; -export interface SessionExitedEvent extends DebugEvent { - body: { - exitCode: number, - sessionId: string - }; -} - -export interface SessionTerminatedEvent extends DebugEvent { - body: { - restart?: boolean, - sessionId: string - }; -} - export class RawDebugSession implements IRawSession { - private debugAdapter: IDebugAdapter; - public emittedStopped: boolean; public readyForBreakpoints: boolean; + public disconnected: boolean; + private debugAdapter: IDebugAdapter; private cachedInitServerP: TPromise; private startTime: number; - public disconnected: boolean; private terminated: boolean; private cancellationTokens: CancellationTokenSource[]; private _capabilities: DebugProtocol.Capabilities; private allThreadsContinued: boolean; private isAttached: boolean; + // DAP events private readonly _onDidInitialize: Emitter; private readonly _onDidStop: Emitter; private readonly _onDidContinued: Emitter; - private readonly _onDidTerminateDebugee: Emitter; + private readonly _onDidTerminateDebugee: Emitter; private readonly _onDidExitDebugee: Emitter; - private readonly _onDidExitAdapter: Emitter<{ sessionId: string }>; private readonly _onDidThread: Emitter; private readonly _onDidOutput: Emitter; private readonly _onDidBreakpoint: Emitter; private readonly _onDidLoadedSource: Emitter; - private readonly _onDidCustomEvent: Emitter; + private readonly _onDidCustomEvent: Emitter; private readonly _onDidEvent: Emitter; + // DA events + private readonly _onDidExitAdapter: Emitter; + constructor( - private sessionId: string, private debugServerPort: number, private _debugger: Debugger, public customTelemetryService: ITelemetryService, @@ -80,17 +67,20 @@ export class RawDebugSession implements IRawSession { this._onDidInitialize = new Emitter(); this._onDidStop = new Emitter(); this._onDidContinued = new Emitter(); - this._onDidTerminateDebugee = new Emitter(); + this._onDidTerminateDebugee = new Emitter(); this._onDidExitDebugee = new Emitter(); - this._onDidExitAdapter = new Emitter<{ sessionId: string }>(); this._onDidThread = new Emitter(); this._onDidOutput = new Emitter(); this._onDidBreakpoint = new Emitter(); this._onDidLoadedSource = new Emitter(); - this._onDidCustomEvent = new Emitter(); + this._onDidCustomEvent = new Emitter(); this._onDidEvent = new Emitter(); + + this._onDidExitAdapter = new Emitter(); } + // DAP events + public get onDidInitialize(): Event { return this._onDidInitialize.event; } @@ -103,7 +93,7 @@ export class RawDebugSession implements IRawSession { return this._onDidContinued.event; } - public get onDidTerminateDebugee(): Event { + public get onDidTerminateDebugee(): Event { return this._onDidTerminateDebugee.event; } @@ -111,10 +101,6 @@ export class RawDebugSession implements IRawSession { return this._onDidExitDebugee.event; } - public get onDidExitAdapter(): Event<{ sessionId: string }> { - return this._onDidExitAdapter.event; - } - public get onDidThread(): Event { return this._onDidThread.event; } @@ -131,7 +117,7 @@ export class RawDebugSession implements IRawSession { return this._onDidLoadedSource.event; } - public get onDidCustomEvent(): Event { + public get onDidCustomEvent(): Event { return this._onDidCustomEvent.event; } @@ -139,6 +125,11 @@ export class RawDebugSession implements IRawSession { return this._onDidEvent.event; } + // DA event + public get onDidExitAdapter(): Event { + return this._onDidExitAdapter.event; + } + private initServer(): TPromise { if (this.cachedInitServerP) { @@ -233,37 +224,49 @@ export class RawDebugSession implements IRawSession { }); } - private onDapEvent(event: DebugEvent): void { - event.sessionId = this.sessionId; + private onDapEvent(event: DebugProtocol.Event): void { - if (event.event === 'loadedSource') { // most frequent comes first - this._onDidLoadedSource.fire(event); - } else if (event.event === 'initialized') { - this.readyForBreakpoints = true; - this._onDidInitialize.fire(event); - } else if (event.event === 'capabilities' && event.body) { - const capabilites = (event).body.capabilities; - this._capabilities = objects.mixin(this._capabilities, capabilites); - } else if (event.event === 'stopped') { - this.emittedStopped = true; - this._onDidStop.fire(event); - } else if (event.event === 'continued') { - this.allThreadsContinued = (event).body.allThreadsContinued === false ? false : true; - this._onDidContinued.fire(event); - } else if (event.event === 'thread') { - this._onDidThread.fire(event); - } else if (event.event === 'output') { - this._onDidOutput.fire(event); - } else if (event.event === 'breakpoint') { - this._onDidBreakpoint.fire(event); - } else if (event.event === 'terminated') { - this._onDidTerminateDebugee.fire(event); - } else if (event.event === 'exit') { - this._onDidExitDebugee.fire(event); - } else { - this._onDidCustomEvent.fire(event); + switch (event.event) { + case 'initialized': + this.readyForBreakpoints = true; + this._onDidInitialize.fire(event); + break; + case 'loadedSource': + this._onDidLoadedSource.fire(event); + break; + case 'capabilities': + if (event.body) { + const capabilites = (event).body.capabilities; + this._capabilities = objects.mixin(this._capabilities, capabilites); + } + break; + case 'stopped': + this.emittedStopped = true; + this._onDidStop.fire(event); + break; + case 'continued': + this.allThreadsContinued = (event).body.allThreadsContinued === false ? false : true; + this._onDidContinued.fire(event); + break; + case 'thread': + this._onDidThread.fire(event); + break; + case 'output': + this._onDidOutput.fire(event); + break; + case 'breakpoint': + this._onDidBreakpoint.fire(event); + break; + case 'terminated': + this._onDidTerminateDebugee.fire(event); + break; + case 'exit': + this._onDidExitDebugee.fire(event); + break; + default: + this._onDidCustomEvent.fire(event); + break; } - this._onDidEvent.fire(event); } @@ -279,7 +282,6 @@ export class RawDebugSession implements IRawSession { if (response) { this._capabilities = objects.mixin(this._capabilities, response.body); } - return response; } @@ -347,11 +349,11 @@ export class RawDebugSession implements IRawSession { } public terminate(restart = false): TPromise { + if (this.capabilities.supportsTerminateRequest && !this.terminated && !this.isAttached) { this.terminated = true; return this.send('terminate', { restart }); } - return this.disconnect(restart); } @@ -508,7 +510,7 @@ export class RawDebugSession implements IRawSession { this.cachedInitServerP = null; } - this._onDidExitAdapter.fire({ sessionId: this.sessionId }); + this._onDidExitAdapter.fire(); this.disconnected = true; if (!this.debugAdapter || this.debugAdapter instanceof SocketDebugAdapter) { return TPromise.as(null); @@ -528,6 +530,6 @@ export class RawDebugSession implements IRawSession { if (!this.disconnected) { this.notificationService.error(nls.localize('debugAdapterCrash', "Debug adapter process has terminated unexpectedly")); } - this._onDidExitAdapter.fire({ sessionId: this.sessionId }); + this._onDidExitAdapter.fire(); } } diff --git a/src/vs/workbench/parts/debug/test/common/mockDebug.ts b/src/vs/workbench/parts/debug/test/common/mockDebug.ts index 33b8a30d907..31156139946 100644 --- a/src/vs/workbench/parts/debug/test/common/mockDebug.ts +++ b/src/vs/workbench/parts/debug/test/common/mockDebug.ts @@ -8,7 +8,7 @@ import { Event } from 'vs/base/common/event'; import { TPromise } from 'vs/base/common/winjs.base'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { Position } from 'vs/editor/common/core/position'; -import { ILaunch, IDebugService, State, DebugEvent, ISession, IConfigurationManager, IStackFrame, IBreakpointData, IBreakpointUpdateData, IConfig, IModel, IViewModel, IRawSession, IBreakpoint, LoadedSourceEvent, IThread, IRawModelUpdate } from 'vs/workbench/parts/debug/common/debug'; +import { ILaunch, IDebugService, State, ISession, IConfigurationManager, IStackFrame, IBreakpointData, IBreakpointUpdateData, IConfig, IModel, IViewModel, IRawSession, IBreakpoint, LoadedSourceEvent, IThread, IRawModelUpdate } from 'vs/workbench/parts/debug/common/debug'; import { Source } from 'vs/workbench/parts/debug/common/debugSource'; import { ISuggestion } from 'vs/editor/common/modes'; @@ -16,6 +16,10 @@ export class MockDebugService implements IDebugService { public _serviceBrand: any; + getSession(sessionId: string): ISession { + return undefined; + } + public get state(): State { return null; } @@ -145,7 +149,7 @@ export class MockSession implements ISession { return null; } - get onDidCustomEvent(): Event { + get onDidCustomEvent(): Event { return null; } diff --git a/src/vs/workbench/parts/debug/test/electron-browser/debugModel.test.ts b/src/vs/workbench/parts/debug/test/electron-browser/debugModel.test.ts index 329ec9d80b1..5b20e4558a4 100644 --- a/src/vs/workbench/parts/debug/test/electron-browser/debugModel.test.ts +++ b/src/vs/workbench/parts/debug/test/electron-browser/debugModel.test.ts @@ -109,12 +109,12 @@ suite('Debug - Model', () => { test('threads simple', () => { const threadId = 1; const threadName = 'firstThread'; - const session = new Session('mock', { resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined, undefined, undefined); + const session = new Session({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined, undefined, undefined); model.addSession(session); assert.equal(model.getSessions().length, 1); model.rawUpdate({ - sessionId: 'mock', + sessionId: session.getId(), threadId: threadId, thread: { id: threadId, @@ -141,13 +141,13 @@ suite('Debug - Model', () => { const stoppedReason = 'breakpoint'; // Add the threads - const session = new Session('mock', { resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined, undefined, undefined); + const session = new Session({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined, undefined, undefined); model.addSession(session); session['_raw'] = rawSession; model.rawUpdate({ - sessionId: 'mock', + sessionId: session.getId(), threadId: threadId1, thread: { id: threadId1, @@ -156,7 +156,7 @@ suite('Debug - Model', () => { }); model.rawUpdate({ - sessionId: 'mock', + sessionId: session.getId(), threadId: threadId2, thread: { id: threadId2, @@ -166,7 +166,7 @@ suite('Debug - Model', () => { // Stopped event with all threads stopped model.rawUpdate({ - sessionId: 'mock', + sessionId: session.getId(), threadId: threadId1, stoppedDetails: { reason: stoppedReason, @@ -234,14 +234,14 @@ suite('Debug - Model', () => { const runningThreadId = 2; const runningThreadName = 'runningThread'; const stoppedReason = 'breakpoint'; - const session = new Session('mock', { resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined, undefined, undefined); + const session = new Session({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined, undefined, undefined); model.addSession(session); session['_raw'] = rawSession; // Add the threads model.rawUpdate({ - sessionId: 'mock', + sessionId: session.getId(), threadId: stoppedThreadId, thread: { id: stoppedThreadId, @@ -250,7 +250,7 @@ suite('Debug - Model', () => { }); model.rawUpdate({ - sessionId: 'mock', + sessionId: session.getId(), threadId: runningThreadId, thread: { id: runningThreadId, @@ -260,7 +260,7 @@ suite('Debug - Model', () => { // Stopped event with only one thread stopped model.rawUpdate({ - sessionId: 'mock', + sessionId: session.getId(), threadId: stoppedThreadId, stoppedDetails: { reason: stoppedReason, @@ -348,7 +348,7 @@ suite('Debug - Model', () => { test('repl expressions', () => { assert.equal(model.getReplElements().length, 0); - const session = new Session('mock', { resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined, undefined, undefined); + const session = new Session({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined, undefined, undefined); model.addSession(session); session['_raw'] = rawSession; @@ -370,7 +370,7 @@ suite('Debug - Model', () => { }); test('stack frame get specific source name', () => { - const session = new Session('mock', { resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined, undefined, undefined); + const session = new Session({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined, undefined, undefined); model.addSession(session); let firstStackFrame: StackFrame;