diff --git a/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts b/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts index 8c8d095db84..c3e41323219 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts @@ -94,7 +94,8 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb // set up a handler to send more this._toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(e => { - if (e) { + // Ignore session only breakpoint events since they should only reflect in the UI + if (e && !e.sessionOnly) { const delta: IBreakpointsDeltaDto = {}; if (e.added) { delta.added = this.convertToDto(e.added); diff --git a/src/vs/workbench/parts/debug/common/debug.ts b/src/vs/workbench/parts/debug/common/debug.ts index 7081afe7c4a..ca2d0ad7dca 100644 --- a/src/vs/workbench/parts/debug/common/debug.ts +++ b/src/vs/workbench/parts/debug/common/debug.ts @@ -337,6 +337,7 @@ export interface IBreakpointsChangeEvent { added?: (IBreakpoint | IFunctionBreakpoint)[]; removed?: (IBreakpoint | IFunctionBreakpoint)[]; changed?: (IBreakpoint | IFunctionBreakpoint)[]; + sessionOnly?: boolean; } // Debug enums diff --git a/src/vs/workbench/parts/debug/common/debugModel.ts b/src/vs/workbench/parts/debug/common/debugModel.ts index 05c412bf1aa..6e8edd9f7cf 100644 --- a/src/vs/workbench/parts/debug/common/debugModel.ts +++ b/src/vs/workbench/parts/debug/common/debugModel.ts @@ -756,13 +756,23 @@ export class BaseBreakpoint extends Enablement implements IBaseBreakpoint { public get verified(): boolean { const data = this.getSessionData(); - return !!(data && data.verified); + return data ? data.verified : true; } public get idFromAdapter(): number { const data = this.getSessionData(); return data ? data.id : undefined; } + + public toJSON(): any { + const result = Object.create(null); + result.enabled = this.enabled; + result.condition = this.condition; + result.hitCondition = this.hitCondition; + result.logMessage = this.logMessage; + + return result; + } } export class Breakpoint extends BaseBreakpoint implements IBreakpoint { @@ -788,7 +798,8 @@ export class Breakpoint extends BaseBreakpoint implements IBreakpoint { public get column(): number { const data = this.getSessionData(); - return data && typeof data.column === 'number' ? data.column : this._column; + // Only respect the column if the user explictly set the column to have an inline breakpoint + return data && typeof data.column === 'number' && typeof this._column === 'number' ? data.column : this._column; } public get message(): string { @@ -811,6 +822,16 @@ export class Breakpoint extends BaseBreakpoint implements IBreakpoint { return data ? data.endColumn : undefined; } + public toJSON(): any { + const result = super.toJSON(); + result.uri = this.uri; + result.lineNumber = this._lineNumber; + result.column = this._column; + result.adapterData = this.adapterData; + + return result; + } + public update(data: IBreakpointUpdateData): void { if (!isUndefinedOrNull(data.lineNumber)) { this._lineNumber = data.lineNumber; @@ -841,6 +862,13 @@ export class FunctionBreakpoint extends BaseBreakpoint implements IFunctionBreak id = generateUuid()) { super(enabled, hitCondition, condition, logMessage, id); } + + public toJSON(): any { + const result = super.toJSON(); + result.name = this.name; + + return result; + } } export class ExceptionBreakpoint extends Enablement implements IExceptionBreakpoint { @@ -848,6 +876,15 @@ export class ExceptionBreakpoint extends Enablement implements IExceptionBreakpo constructor(public filter: string, public label: string, enabled: boolean) { super(enabled, generateUuid()); } + + public toJSON(): any { + const result = Object.create(null); + result.filter = this.filter; + result.label = this.label; + result.enabled = this.enabled; + + return result; + } } export class ThreadAndSessionIds implements ITreeElement { @@ -864,6 +901,7 @@ export class Model implements IModel { 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; @@ -958,7 +996,7 @@ export class Model implements IModel { return thread.fetchCallStack(); } - public getBreakpoints(filter?: { uri?: uri, lineNumber?: number, column?: number, enabledOnly?: boolean }): Breakpoint[] { + public getBreakpoints(filter?: { uri?: uri, lineNumber?: number, column?: number, enabledOnly?: boolean }): IBreakpoint[] { if (filter) { const uriStr = filter.uri ? filter.uri.toString() : undefined; return this.breakpoints.filter(bp => { @@ -982,7 +1020,7 @@ export class Model implements IModel { return this.breakpoints; } - public getFunctionBreakpoints(): FunctionBreakpoint[] { + public getFunctionBreakpoints(): IFunctionBreakpoint[] { return this.functionBreakpoints; } @@ -992,6 +1030,11 @@ export class Model implements IModel { public setExceptionBreakpoints(data: DebugProtocol.ExceptionBreakpointsFilter[]): void { if (data) { + if (this.exceptionBreakpoints.length === data.length && this.exceptionBreakpoints.every((exbp, i) => exbp.filter === data[i].filter && exbp.label === data[i].label)) { + // No change + return; + } + this.exceptionBreakpoints = data.map(d => { const ebp = this.exceptionBreakpoints.filter(ebp => ebp.filter === d.filter).pop(); return new ExceptionBreakpoint(d.filter, d.label, ebp ? ebp.enabled : d.default); @@ -1011,6 +1054,7 @@ export class Model implements IModel { public addBreakpoints(uri: uri, rawData: IBreakpointData[], fireEvent = true): IBreakpoint[] { const newBreakpoints = rawData.map(rawBp => new Breakpoint(uri, rawBp.lineNumber, rawBp.column, rawBp.enabled, rawBp.condition, rawBp.hitCondition, rawBp.logMessage, undefined, rawBp.id)); + newBreakpoints.forEach(bp => bp.setSessionId(this.breakpointsSessionId)); this.breakpoints = this.breakpoints.concat(newBreakpoints); this.breakpointsActivated = true; this.sortAndDeDup(); @@ -1040,6 +1084,35 @@ export class Model implements IModel { this._onDidChangeBreakpoints.fire({ changed: updated }); } + public setBreakpointSessionData(sessionId: string, data: { [id: string]: DebugProtocol.Breakpoint }): void { + this.breakpoints.forEach(bp => { + const bpData = data[bp.getId()]; + if (bpData) { + bp.setSessionData(sessionId, bpData); + } + }); + this.functionBreakpoints.forEach(fbp => { + const fbpData = data[fbp.getId()]; + if (fbpData) { + fbp.setSessionData(sessionId, fbpData); + } + }); + + this._onDidChangeBreakpoints.fire({ + sessionOnly: true + }); + } + + public setBreakpointsSessionId(sessionId: string): void { + this.breakpointsSessionId = sessionId; + this.breakpoints.forEach(bp => bp.setSessionId(sessionId)); + this.functionBreakpoints.forEach(fbp => fbp.setSessionId(sessionId)); + + this._onDidChangeBreakpoints.fire({ + sessionOnly: true + }); + } + private sortAndDeDup(): void { this.breakpoints = this.breakpoints.sort((first, second) => { if (first.uri.toString() !== second.uri.toString()) { diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index c4295e65fd2..7dd9d71ee34 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -138,6 +138,10 @@ export class DebugService implements debug.IDebugService { this.lifecycleService.onShutdown(this.store, this); this.lifecycleService.onShutdown(this.dispose, this); this.toDispose.push(this.broadcastService.onBroadcast(this.onBroadcast, this)); + this.toDispose.push(this.viewModel.onDidFocusSession(s => { + const id = s ? s.getId() : undefined; + this.model.setBreakpointsSessionId(id); + })); } private onBroadcast(broadcast: IBroadcast): void { @@ -425,10 +429,10 @@ export class DebugService implements debug.IDebugService { if (!breakpoint.column) { event.body.breakpoint.column = undefined; } - breakpoint.setSessionData(session.getId(), event.body.breakpoint); + this.model.setBreakpointSessionData(session.getId(), { [breakpoint.getId()]: event.body.breakpoint }); } if (functionBreakpoint) { - functionBreakpoint.setSessionData(session.getId(), event.body.breakpoint); + this.model.setBreakpointSessionData(session.getId(), { [functionBreakpoint.getId()]: event.body.breakpoint }); } } })); @@ -493,7 +497,7 @@ export class DebugService implements debug.IDebugService { let result: ExceptionBreakpoint[]; try { result = JSON.parse(this.storageService.get(DEBUG_EXCEPTION_BREAKPOINTS_KEY, StorageScope.WORKSPACE, '[]')).map((exBreakpoint: any) => { - return new ExceptionBreakpoint(exBreakpoint.filter || exBreakpoint.name, exBreakpoint.label, exBreakpoint.enabled); + return new ExceptionBreakpoint(exBreakpoint.filter, exBreakpoint.label, exBreakpoint.enabled); }); } catch (e) { } @@ -611,7 +615,7 @@ export class DebugService implements debug.IDebugService { public addBreakpoints(uri: uri, rawBreakpoints: debug.IBreakpointData[]): TPromise { const breakpoints = this.model.addBreakpoints(uri, rawBreakpoints); - rawBreakpoints.forEach(rbp => aria.status(nls.localize('breakpointAdded', "Added breakpoint, line {0}, file {1}", rbp.lineNumber, uri.fsPath))); + breakpoints.forEach(bp => aria.status(nls.localize('breakpointAdded', "Added breakpoint, line {0}, file {1}", bp.lineNumber, uri.fsPath))); return this.sendBreakpoints(uri).then(() => breakpoints); } @@ -1247,9 +1251,11 @@ export class DebugService implements debug.IDebugService { return; } + const data = Object.create(null); for (let i = 0; i < breakpointsToSend.length; i++) { - breakpointsToSend[i].setSessionData(raw.getId(), response.body.breakpoints[i]); + data[breakpointsToSend[i].getId()] = response.body.breakpoints[i]; } + this.model.setBreakpointSessionData(raw.getId(), data); }); }; @@ -1269,9 +1275,11 @@ export class DebugService implements debug.IDebugService { return; } + const data = Object.create(null); for (let i = 0; i < breakpointsToSend.length; i++) { - breakpointsToSend[i].setSessionData(raw.getId(), response.body.breakpoints[i]); + data[breakpointsToSend[i].getId()] = response.body.breakpoints[i]; } + this.model.setBreakpointSessionData(raw.getId(), data); }); }; @@ -1316,7 +1324,6 @@ export class DebugService implements debug.IDebugService { } private store(): void { - // TODO@Isidor proper storage of breakpoints const breakpoints = this.model.getBreakpoints(); if (breakpoints.length) { this.storageService.store(DEBUG_BREAKPOINTS_KEY, JSON.stringify(breakpoints), StorageScope.WORKSPACE);