From aa351d8293e1ffe3be31e0ad1e22d5abafb67bce Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 5 Oct 2018 11:52:57 +0200 Subject: [PATCH] debug: keep repl elements per session --- .../mainThreadDebugService.ts | 5 +- .../parts/debug/browser/debugActions.ts | 23 ++---- .../parts/debug/browser/debugEditorActions.ts | 4 +- src/vs/workbench/parts/debug/common/debug.ts | 30 +++----- .../parts/debug/common/debugModel.ts | 57 +------------- .../debug/electron-browser/debugService.ts | 32 +------- .../debug/electron-browser/debugSession.ts | 77 +++++++++++++++++-- .../parts/debug/electron-browser/repl.ts | 23 +++--- .../parts/debug/test/common/mockDebug.ts | 16 +++- .../test/electron-browser/debugModel.test.ts | 23 +++--- 10 files changed, 141 insertions(+), 149 deletions(-) diff --git a/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts b/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts index 63f671e4a84..f859ff040d4 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts @@ -205,7 +205,10 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb public $appendDebugConsole(value: string): Thenable { // Use warning as severity to get the orange color for messages coming from the debug extension - this.debugService.logToRepl(value, severity.Warning); + const session = this.debugService.getViewModel().focusedSession; + if (session) { + session.appendToRepl(value, severity.Warning); + } return TPromise.wrap(undefined); } diff --git a/src/vs/workbench/parts/debug/browser/debugActions.ts b/src/vs/workbench/parts/debug/browser/debugActions.ts index 2fed9479bfa..6e53111f8ee 100644 --- a/src/vs/workbench/parts/debug/browser/debugActions.ts +++ b/src/vs/workbench/parts/debug/browser/debugActions.ts @@ -239,9 +239,7 @@ export class RestartAction extends AbstractDebugAction { return this.startAction.run(); } - if (this.debugService.getModel().getSessions().length <= 1) { - this.debugService.removeReplExpressions(); - } + session.removeReplExpressions(); return this.debugService.restartSession(session); } @@ -692,8 +690,11 @@ export class ClearReplAction extends AbstractDebugAction { } public run(): TPromise { - this.debugService.removeReplExpressions(); - aria.status(nls.localize('debugConsoleCleared', "Debug console was cleared")); + const session = this.debugService.getViewModel().focusedSession; + if (session) { + session.removeReplExpressions(); + aria.status(nls.localize('debugConsoleCleared', "Debug console was cleared")); + } // focus back to repl return this.panelService.openPanel(REPL_ID, true); @@ -706,7 +707,6 @@ export class ToggleReplAction extends TogglePanelAction { private toDispose: lifecycle.IDisposable[]; constructor(id: string, label: string, - @IDebugService private debugService: IDebugService, @IPartService partService: IPartService, @IPanelService panelService: IPanelService ) { @@ -716,12 +716,6 @@ export class ToggleReplAction extends TogglePanelAction { } private registerListeners(): void { - this.toDispose.push(this.debugService.getModel().onDidChangeReplElements(() => { - if (!this.isReplVisible()) { - this.class = 'debug-action toggle-repl notification'; - this.tooltip = nls.localize('unreadOutput', "New Output in Debug Console"); - } - })); this.toDispose.push(this.panelService.onDidPanelOpen(panel => { if (panel.getId() === REPL_ID) { this.class = 'debug-action toggle-repl'; @@ -730,11 +724,6 @@ export class ToggleReplAction extends TogglePanelAction { })); } - private isReplVisible(): boolean { - const panel = this.panelService.getActivePanel(); - return panel && panel.getId() === REPL_ID; - } - public dispose(): void { super.dispose(); this.toDispose = lifecycle.dispose(this.toDispose); diff --git a/src/vs/workbench/parts/debug/browser/debugEditorActions.ts b/src/vs/workbench/parts/debug/browser/debugEditorActions.ts index c34c2c81431..ca7e8ac1021 100644 --- a/src/vs/workbench/parts/debug/browser/debugEditorActions.ts +++ b/src/vs/workbench/parts/debug/browser/debugEditorActions.ts @@ -159,7 +159,9 @@ class SelectionToReplAction extends EditorAction { const panelService = accessor.get(IPanelService); const text = editor.getModel().getValueInRange(editor.getSelection()); - return debugService.addReplExpression(text) + const viewModel = debugService.getViewModel(); + const session = viewModel.focusedSession; + return session.addReplExpression(viewModel.focusedStackFrame, text) .then(() => panelService.openPanel(REPL_ID, true)) .then(_ => void 0); } diff --git a/src/vs/workbench/parts/debug/common/debug.ts b/src/vs/workbench/parts/debug/common/debug.ts index 188ae7ac40b..01ef8b1a61b 100644 --- a/src/vs/workbench/parts/debug/common/debug.ts +++ b/src/vs/workbench/parts/debug/common/debug.ts @@ -152,6 +152,16 @@ export interface IDebugSession extends ITreeElement { setConfiguration(configuration: { resolved: IConfig, unresolved: IConfig }): void; rawUpdate(data: IRawModelUpdate): void; + getThread(threadId: number): IThread; + getAllThreads(): ReadonlyArray; + clearThreads(removeThreads: boolean, reference?: number): void; + + getReplElements(): ReadonlyArray; + + removeReplExpressions(): void; + addReplExpression(stackFrame: IStackFrame, name: string): TPromise; + appendToRepl(data: string | IExpression, severity: severity, source?: IReplElementSource): void; + // session events readonly onDidEndAdapter: Event; readonly onDidChangeState: Event; @@ -200,10 +210,6 @@ export interface IDebugSession extends ITreeElement { setVariable(variablesReference: number, name: string, value: string): TPromise; loadSource(resource: uri): TPromise; getLoadedSources(): TPromise; - - getThread(threadId: number): IThread; - getAllThreads(): ReadonlyArray; - clearThreads(removeThreads: boolean, reference?: number): void; } export interface IThread extends ITreeElement { @@ -379,7 +385,6 @@ export interface IDebugModel extends ITreeElement { onDidChangeBreakpoints: Event; onDidChangeCallStack: Event; onDidChangeWatchExpressions: Event; - onDidChangeReplElements: Event; } /** @@ -721,21 +726,6 @@ export interface IDebugService { */ sendAllBreakpoints(session?: IDebugSession): TPromise; - /** - * Adds a new expression to the repl. - */ - addReplExpression(name: string): TPromise; - - /** - * Removes all repl expressions. - */ - removeReplExpressions(): void; - - /** - * Appends the passed string to the debug repl. - */ - logToRepl(value: string | IExpression, sev?: severity, source?: IReplElementSource): void; - /** * Adds a new watch expression and evaluates it against the debug adapter. */ diff --git a/src/vs/workbench/parts/debug/common/debugModel.ts b/src/vs/workbench/parts/debug/common/debugModel.ts index 2653d0ea6af..645863e5415 100644 --- a/src/vs/workbench/parts/debug/common/debugModel.ts +++ b/src/vs/workbench/parts/debug/common/debugModel.ts @@ -25,8 +25,6 @@ import { sep } from 'vs/base/common/paths'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -const MAX_REPL_LENGTH = 10000; - export abstract class AbstractReplElement implements IReplElement { private static ID_COUNTER = 0; @@ -728,13 +726,11 @@ export class DebugModel implements IDebugModel { private sessions: IDebugSession[]; private toDispose: lifecycle.IDisposable[]; - private replElements: IReplElement[]; private schedulers = new Map(); private breakpointsSessionId: string; private readonly _onDidChangeBreakpoints: Emitter; private readonly _onDidChangeCallStack: Emitter; private readonly _onDidChangeWatchExpressions: Emitter; - private readonly _onDidChangeREPLElements: Emitter; constructor( private breakpoints: Breakpoint[], @@ -745,12 +741,10 @@ export class DebugModel implements IDebugModel { private textFileService: ITextFileService ) { this.sessions = []; - this.replElements = []; this.toDispose = []; this._onDidChangeBreakpoints = new Emitter(); this._onDidChangeCallStack = new Emitter(); this._onDidChangeWatchExpressions = new Emitter(); - this._onDidChangeREPLElements = new Emitter(); } public getId(): string { @@ -782,10 +776,6 @@ export class DebugModel implements IDebugModel { return this._onDidChangeWatchExpressions.event; } - public get onDidChangeReplElements(): Event { - return this._onDidChangeREPLElements.event; - } - public rawUpdate(data: IRawModelUpdate): void { let session = this.sessions.filter(p => p.getId() === data.sessionId).pop(); if (session) { @@ -1015,51 +1005,8 @@ export class DebugModel implements IDebugModel { this._onDidChangeBreakpoints.fire({ removed: removed }); } - public getReplElements(): IReplElement[] { - return this.replElements; - } - - public addReplExpression(session: IDebugSession, stackFrame: IStackFrame, name: string): TPromise { - const expression = new Expression(name); - this.addReplElements([expression]); - return expression.evaluate(session, stackFrame, 'repl') - .then(() => this._onDidChangeREPLElements.fire()); - } - - public appendToRepl(data: string | IExpression, severity: severity, source?: IReplElementSource): void { - if (typeof data === 'string') { - const previousElement = this.replElements.length && (this.replElements[this.replElements.length - 1] as SimpleReplElement); - - const toAdd = data.split('\n').map((line, index) => new SimpleReplElement(line, severity, index === 0 ? source : undefined)); - if (previousElement && previousElement.value === '') { - // remove potential empty lines between different repl types - this.replElements.pop(); - } else if (previousElement instanceof SimpleReplElement && severity === previousElement.severity && toAdd.length && toAdd[0].sourceData === previousElement.sourceData) { - previousElement.value += toAdd.shift().value; - } - this.addReplElements(toAdd); - } else { - // TODO@Isidor hack, we should introduce a new type which is an output that can fetch children like an expression - (data).severity = severity; - (data).sourceData = source; - this.addReplElements([data]); - } - - this._onDidChangeREPLElements.fire(); - } - - private addReplElements(newElements: IReplElement[]): void { - this.replElements.push(...newElements); - if (this.replElements.length > MAX_REPL_LENGTH) { - this.replElements.splice(0, this.replElements.length - MAX_REPL_LENGTH); - } - } - - public removeReplExpressions(): void { - if (this.replElements.length > 0) { - this.replElements = []; - this._onDidChangeREPLElements.fire(); - } + public getReplElements(): ReadonlyArray { + return this.sessions.map(s => s.getReplElements()).reduce((left, right) => left.concat(right), []); } public getWatchExpressions(): Expression[] { diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index 0e4e8b9f834..ac510c74d58 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -46,7 +46,7 @@ import { IAction, Action } from 'vs/base/common/actions'; import { deepClone, equals } from 'vs/base/common/objects'; import { DebugSession } from 'vs/workbench/parts/debug/electron-browser/debugSession'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; -import { IDebugService, State, IDebugSession, CONTEXT_DEBUG_TYPE, CONTEXT_DEBUG_STATE, CONTEXT_IN_DEBUG_MODE, IThread, IDebugConfiguration, VIEWLET_ID, REPL_ID, IConfig, ILaunch, IViewModel, IConfigurationManager, IDebugModel, IReplElementSource, IEnablement, IBreakpoint, IBreakpointData, IExpression, ICompound, IGlobalConfig, IStackFrame, AdapterEndEvent } from 'vs/workbench/parts/debug/common/debug'; +import { IDebugService, State, IDebugSession, CONTEXT_DEBUG_TYPE, CONTEXT_DEBUG_STATE, CONTEXT_IN_DEBUG_MODE, IThread, IDebugConfiguration, VIEWLET_ID, REPL_ID, IConfig, ILaunch, IViewModel, IConfigurationManager, IDebugModel, IReplElementSource, IEnablement, IBreakpoint, IBreakpointData, ICompound, IGlobalConfig, IStackFrame, AdapterEndEvent } from 'vs/workbench/parts/debug/common/debug'; import { isExtensionHostDebugging } from 'vs/workbench/parts/debug/common/debugUtils'; import { RunOnceScheduler } from 'vs/base/common/async'; @@ -266,9 +266,7 @@ export class DebugService implements IDebugService { this.textFileService.saveAll().then(() => this.configurationService.reloadConfiguration(launch ? launch.workspace : undefined).then(() => this.extensionService.whenInstalledExtensionsRegistered().then(() => { - // If it is the very first start debugging we need to clear the repl and our sessions map if (this.model.getSessions().length === 0) { - this.removeReplExpressions(); this.allSessions.clear(); } @@ -786,16 +784,6 @@ export class DebugService implements IDebugService { //---- REPL - addReplExpression(name: string): TPromise { - return this.model.addReplExpression(this.viewModel.focusedSession, this.viewModel.focusedStackFrame, name) - // Evaluate all watch expressions and fetch variables again since repl evaluation might have changed some. - .then(() => this.focusStackFrame(this.viewModel.focusedStackFrame, this.viewModel.focusedThread, this.viewModel.focusedSession)); - } - - removeReplExpressions(): void { - this.model.removeReplExpressions(); - } - private addToRepl(session: IDebugSession, extensionOutput: IRemoteConsoleLog) { let sev = extensionOutput.severity === 'warn' ? severity.Warning : extensionOutput.severity === 'error' ? severity.Error : severity.Info; @@ -836,12 +824,12 @@ export class DebugService implements IDebugService { // flush any existing simple values logged if (simpleVals.length) { - this.logToRepl(simpleVals.join(' '), sev, source); + session.appendToRepl(simpleVals.join(' '), sev, source); simpleVals = []; } // show object - this.logToRepl(new RawObjectReplElement((a).prototype, a, undefined, nls.localize('snapshotObj', "Only primitive values are shown for this object.")), sev, source); + session.appendToRepl(new RawObjectReplElement((a).prototype, a, undefined, nls.localize('snapshotObj', "Only primitive values are shown for this object.")), sev, source); } // string: watch out for % replacement directive @@ -871,22 +859,10 @@ export class DebugService implements IDebugService { // flush simple values // always append a new line for output coming from an extension such that separate logs go to separate lines #23695 if (simpleVals.length) { - this.logToRepl(simpleVals.join(' ') + '\n', sev, source); + session.appendToRepl(simpleVals.join(' ') + '\n', sev, source); } } - logToRepl(value: string | IExpression, sev = severity.Info, source?: IReplElementSource): void { - const clearAnsiSequence = '\u001b[2J'; - if (typeof value === 'string' && value.indexOf(clearAnsiSequence) >= 0) { - // [2J is the ansi escape sequence for clearing the display http://ascii-table.com/ansi-escape-sequences.php - this.model.removeReplExpressions(); - this.model.appendToRepl(nls.localize('consoleCleared', "Console was cleared"), severity.Ignore); - value = value.substr(value.lastIndexOf(clearAnsiSequence) + clearAnsiSequence.length); - } - - this.model.appendToRepl(value, sev, source); - } - //---- watches addWatchExpression(name: string): void { diff --git a/src/vs/workbench/parts/debug/electron-browser/debugSession.ts b/src/vs/workbench/parts/debug/electron-browser/debugSession.ts index 3a31c8af283..15e13f7d98d 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugSession.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugSession.ts @@ -13,10 +13,10 @@ import { Event, Emitter } from 'vs/base/common/event'; import { CompletionItem, completionKindFromLegacyString } from 'vs/editor/common/modes'; import { Position } from 'vs/editor/common/core/position'; import * as aria from 'vs/base/browser/ui/aria/aria'; -import { IDebugSession, IConfig, IThread, IRawModelUpdate, IDebugService, IRawStoppedDetails, State, LoadedSourceEvent, IFunctionBreakpoint, IExceptionBreakpoint, ActualBreakpoints, IBreakpoint, IExceptionInfo, AdapterEndEvent, IDebugger, VIEWLET_ID, IDebugConfiguration } from 'vs/workbench/parts/debug/common/debug'; +import { IDebugSession, IConfig, IThread, IRawModelUpdate, IDebugService, IRawStoppedDetails, State, LoadedSourceEvent, IFunctionBreakpoint, IExceptionBreakpoint, ActualBreakpoints, IBreakpoint, IExceptionInfo, AdapterEndEvent, IDebugger, VIEWLET_ID, IDebugConfiguration, IReplElement, IStackFrame, IExpression, IReplElementSource } 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, DebugModel } from 'vs/workbench/parts/debug/common/debugModel'; +import { Thread, ExpressionContainer, DebugModel, Expression, SimpleReplElement } from 'vs/workbench/parts/debug/common/debugModel'; import { RawDebugSession } from 'vs/workbench/parts/debug/electron-browser/rawDebugSession'; import product from 'vs/platform/node/product'; import { INotificationService } from 'vs/platform/notification/common/notification'; @@ -32,6 +32,8 @@ import { Range } from 'vs/editor/common/core/range'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; +const MAX_REPL_LENGTH = 10000; + export class DebugSession implements IDebugSession { private id: string; @@ -41,6 +43,7 @@ export class DebugSession implements IDebugSession { private threads = new Map(); private rawListeners: IDisposable[] = []; private fetchThreadsScheduler: RunOnceScheduler; + private replElements: IReplElement[] = []; private readonly _onDidChangeState = new Emitter(); private readonly _onDidEndAdapter = new Emitter(); @@ -48,6 +51,7 @@ export class DebugSession implements IDebugSession { private readonly _onDidLoadedSource = new Emitter(); private readonly _onDidCustomEvent = new Emitter(); + private readonly _onDidChangeREPLElements = new Emitter(); constructor( private _configuration: { resolved: IConfig, unresolved: IConfig }, @@ -109,6 +113,10 @@ export class DebugSession implements IDebugSession { return this._onDidEndAdapter.event; } + get onDidChangeReplElements(): Event { + return this._onDidChangeREPLElements.event; + } + //---- DAP events get onDidCustomEvent(): Event { @@ -119,7 +127,6 @@ export class DebugSession implements IDebugSession { return this._onDidLoadedSource.event; } - //---- DAP requests /** @@ -673,11 +680,11 @@ export class DebugSession implements IDebugSession { return Promise.all(waitFor).then(() => children.forEach(child => { // Since we can not display multiple trees in a row, we are displaying these variables one after the other (ignoring their names) child.name = null; - this.debugService.logToRepl(child, outputSeverity, source); + this.appendToRepl(child, outputSeverity, source); })); })); } else if (typeof event.body.output === 'string') { - Promise.all(waitFor).then(() => this.debugService.logToRepl(event.body.output, outputSeverity, source)); + Promise.all(waitFor).then(() => this.appendToRepl(event.body.output, outputSeverity, source)); } Promise.all(outputPromises).then(() => outputPromises = []); })); @@ -775,4 +782,64 @@ export class DebugSession implements IDebugSession { private getUriKey(uri: URI): string { return platform.isLinux ? uri.toString() : uri.toString().toLowerCase(); } + + // REPL + + public getReplElements(): ReadonlyArray { + return this.replElements; + } + + public addReplExpression(stackFrame: IStackFrame, name: string): TPromise { + const expression = new Expression(name); + this.addReplElements([expression]); + const viewModel = this.debugService.getViewModel(); + return expression.evaluate(this, stackFrame, 'repl') + .then(() => this._onDidChangeREPLElements.fire()) + // Evaluate all watch expressions and fetch variables again since repl evaluation might have changed some. + .then(() => this.debugService.focusStackFrame(viewModel.focusedStackFrame, viewModel.focusedThread, viewModel.focusedSession)); + } + + public appendToRepl(data: string | IExpression, sev: severity, source?: IReplElementSource): void { + const clearAnsiSequence = '\u001b[2J'; + if (typeof data === 'string' && data.indexOf(clearAnsiSequence) >= 0) { + // [2J is the ansi escape sequence for clearing the display http://ascii-table.com/ansi-escape-sequences.php + this.removeReplExpressions(); + this.appendToRepl(nls.localize('consoleCleared', "Console was cleared"), severity.Ignore); + data = data.substr(data.lastIndexOf(clearAnsiSequence) + clearAnsiSequence.length); + } + + if (typeof data === 'string') { + const previousElement = this.replElements.length && (this.replElements[this.replElements.length - 1] as SimpleReplElement); + + const toAdd = data.split('\n').map((line, index) => new SimpleReplElement(line, sev, index === 0 ? source : undefined)); + if (previousElement && previousElement.value === '') { + // remove potential empty lines between different repl types + this.replElements.pop(); + } else if (previousElement instanceof SimpleReplElement && sev === previousElement.severity && toAdd.length && toAdd[0].sourceData === previousElement.sourceData) { + previousElement.value += toAdd.shift().value; + } + this.addReplElements(toAdd); + } else { + // TODO@Isidor hack, we should introduce a new type which is an output that can fetch children like an expression + (data).severity = sev; + (data).sourceData = source; + this.addReplElements([data]); + } + + this._onDidChangeREPLElements.fire(); + } + + private addReplElements(newElements: IReplElement[]): void { + this.replElements.push(...newElements); + if (this.replElements.length > MAX_REPL_LENGTH) { + this.replElements.splice(0, this.replElements.length - MAX_REPL_LENGTH); + } + } + + removeReplExpressions(): void { + if (this.replElements.length > 0) { + this.replElements = []; + this._onDidChangeREPLElements.fire(); + } + } } diff --git a/src/vs/workbench/parts/debug/electron-browser/repl.ts b/src/vs/workbench/parts/debug/electron-browser/repl.ts index 569e0f1fddc..91385d3cd89 100644 --- a/src/vs/workbench/parts/debug/electron-browser/repl.ts +++ b/src/vs/workbench/parts/debug/electron-browser/repl.ts @@ -106,9 +106,10 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati } private registerListeners(): void { - this._register(this.debugService.getModel().onDidChangeReplElements(() => { - this.refreshReplElements(this.debugService.getModel().getReplElements().length === 0); - })); + // TODO@Isidor + // this._register(this.debugService.getModel().onDidChangeReplElements(() => { + // this.refreshReplElements(this.debugService.getModel().getReplElements().length === 0); + // })); this._register(this.panelService.onDidPanelOpen(panel => this.refreshReplElements(true))); } @@ -235,12 +236,16 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati } public acceptReplInput(): void { - this.debugService.addReplExpression(this.replInput.getValue()); - this.history.add(this.replInput.getValue()); - this.replInput.setValue(''); - // Trigger a layout to shrink a potential multi line input - this.replInputHeight = Repl.REPL_INPUT_INITIAL_HEIGHT; - this.layout(this.dimension); + const viewModel = this.debugService.getViewModel(); + const session = viewModel.focusedSession; + if (session) { + session.addReplExpression(viewModel.focusedStackFrame, this.replInput.getValue()); + this.history.add(this.replInput.getValue()); + this.replInput.setValue(''); + // Trigger a layout to shrink a potential multi line input + this.replInputHeight = Repl.REPL_INPUT_INITIAL_HEIGHT; + this.layout(this.dimension); + } } public getVisibleContent(): string { diff --git a/src/vs/workbench/parts/debug/test/common/mockDebug.ts b/src/vs/workbench/parts/debug/test/common/mockDebug.ts index 5bfe5f8f95c..d975e266b31 100644 --- a/src/vs/workbench/parts/debug/test/common/mockDebug.ts +++ b/src/vs/workbench/parts/debug/test/common/mockDebug.ts @@ -8,9 +8,10 @@ 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, IDebugSession, IConfigurationManager, IStackFrame, IBreakpointData, IBreakpointUpdateData, IConfig, IDebugModel, IViewModel, IBreakpoint, LoadedSourceEvent, IThread, IRawModelUpdate, ActualBreakpoints, IFunctionBreakpoint, IExceptionBreakpoint, IDebugger, IExceptionInfo, AdapterEndEvent } from 'vs/workbench/parts/debug/common/debug'; +import { ILaunch, IDebugService, State, IDebugSession, IConfigurationManager, IStackFrame, IBreakpointData, IBreakpointUpdateData, IConfig, IDebugModel, IViewModel, IBreakpoint, LoadedSourceEvent, IThread, IRawModelUpdate, ActualBreakpoints, IFunctionBreakpoint, IExceptionBreakpoint, IDebugger, IExceptionInfo, AdapterEndEvent, IReplElement, IExpression, IReplElementSource } from 'vs/workbench/parts/debug/common/debug'; import { Source } from 'vs/workbench/parts/debug/common/debugSource'; import { CompletionItem } from 'vs/editor/common/modes'; +import Severity from 'vs/base/common/severity'; export class MockDebugService implements IDebugService { @@ -117,7 +118,7 @@ export class MockDebugService implements IDebugService { return null; } - public logToRepl(value: string): void { } + public logToRepl(session: IDebugSession, value: string): void { } public sourceIsNotAvailable(uri: uri): void { } @@ -127,6 +128,17 @@ export class MockDebugService implements IDebugService { } export class MockSession implements IDebugSession { + getReplElements(): ReadonlyArray { + return []; + } + + removeReplExpressions(): void { } + + addReplExpression(stackFrame: IStackFrame, name: string): TPromise { + return TPromise.as(void 0); + } + + appendToRepl(data: string | IExpression, severity: Severity, source?: IReplElementSource): void { } configuration: IConfig = { type: 'mock', request: 'launch' }; unresolvedConfiguration: IConfig = { type: 'mock', request: 'launch' }; 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 fb219ec4024..a6e624241c6 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 @@ -354,9 +354,9 @@ suite('Debug - Model', () => { session['raw'] = rawSession; const thread = new Thread(session, 'mockthread', 1); const stackFrame = new StackFrame(thread, 1, null, 'app.js', 'normal', { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 10 }, 1); - model.addReplExpression(session, stackFrame, 'myVariable').then(); - model.addReplExpression(session, stackFrame, 'myVariable').then(); - model.addReplExpression(session, stackFrame, 'myVariable').then(); + session.addReplExpression(stackFrame, 'myVariable').then(); + session.addReplExpression(stackFrame, 'myVariable').then(); + session.addReplExpression(stackFrame, 'myVariable').then(); assert.equal(model.getReplElements().length, 3); model.getReplElements().forEach(re => { @@ -365,7 +365,7 @@ suite('Debug - Model', () => { assert.equal((re).reference, 0); }); - model.removeReplExpressions(); + session.removeReplExpressions(); assert.equal(model.getReplElements().length, 0); }); @@ -401,10 +401,11 @@ suite('Debug - Model', () => { // Repl output test('repl output', () => { - model.appendToRepl('first line\n', severity.Error); - model.appendToRepl('second line', severity.Error); - model.appendToRepl('third line', severity.Warning); - model.appendToRepl('fourth line', severity.Error); + const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined, undefined, undefined, undefined, undefined, undefined); + session.appendToRepl('first line\n', severity.Error); + session.appendToRepl('second line', severity.Error); + session.appendToRepl('third line', severity.Warning); + session.appendToRepl('fourth line', severity.Error); let elements = model.getReplElements(); assert.equal(elements.length, 4); @@ -417,19 +418,19 @@ suite('Debug - Model', () => { assert.equal(elements[3].value, 'fourth line'); assert.equal(elements[3].severity, severity.Error); - model.appendToRepl('1', severity.Warning); + session.appendToRepl('1', severity.Warning); elements = model.getReplElements(); assert.equal(elements.length, 5); assert.equal(elements[4].value, '1'); assert.equal(elements[4].severity, severity.Warning); const keyValueObject = { 'key1': 2, 'key2': 'value' }; - model.appendToRepl(new RawObjectReplElement('fake', keyValueObject), null); + session.appendToRepl(new RawObjectReplElement('fake', keyValueObject), null); const element = model.getReplElements()[5]; assert.equal(element.value, 'Object'); assert.deepEqual(element.valueObj, keyValueObject); - model.removeReplExpressions(); + session.removeReplExpressions(); assert.equal(model.getReplElements().length, 0); }); });