mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-01 17:23:35 -05:00
Merge from vscode 70dc55955d586ebd427658b43cdb344f2047f9c2 (#6789)
This commit is contained in:
@@ -8,7 +8,7 @@ import * as resources from 'vs/base/common/resources';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { IAction, Action } from 'vs/base/common/actions';
|
||||
import { IDebugService, IBreakpoint, CONTEXT_BREAKPOINTS_FOCUSED, EDITOR_CONTRIBUTION_ID, State, DEBUG_SCHEME, IFunctionBreakpoint, IExceptionBreakpoint, IEnablement, IDebugEditorContribution } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { ExceptionBreakpoint, FunctionBreakpoint, Breakpoint } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { ExceptionBreakpoint, FunctionBreakpoint, Breakpoint, DataBreakpoint } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { AddFunctionBreakpointAction, ToggleBreakpointsActivatedAction, RemoveAllBreakpointsAction, RemoveBreakpointAction, EnableAllBreakpointsAction, DisableAllBreakpointsAction, ReapplyBreakpointsAction } from 'vs/workbench/contrib/debug/browser/debugActions';
|
||||
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -74,6 +74,7 @@ export class BreakpointsView extends ViewletPanel {
|
||||
this.instantiationService.createInstance(BreakpointsRenderer),
|
||||
new ExceptionBreakpointsRenderer(this.debugService),
|
||||
this.instantiationService.createInstance(FunctionBreakpointsRenderer),
|
||||
this.instantiationService.createInstance(DataBreakpointsRenderer),
|
||||
new FunctionBreakpointInputRenderer(this.debugService, this.contextViewService, this.themeService)
|
||||
], {
|
||||
identityProvider: { getId: (element: IEnablement) => element.getId() },
|
||||
@@ -91,7 +92,7 @@ export class BreakpointsView extends ViewletPanel {
|
||||
|
||||
this._register(this.list.onContextMenu(this.onListContextMenu, this));
|
||||
|
||||
this._register(this.list.onDidOpen(e => {
|
||||
this._register(this.list.onDidOpen(async e => {
|
||||
let isSingleClick = false;
|
||||
let isDoubleClick = false;
|
||||
let isMiddleClick = false;
|
||||
@@ -110,9 +111,11 @@ export class BreakpointsView extends ViewletPanel {
|
||||
|
||||
if (isMiddleClick) {
|
||||
if (element instanceof Breakpoint) {
|
||||
this.debugService.removeBreakpoints(element.getId());
|
||||
await this.debugService.removeBreakpoints(element.getId());
|
||||
} else if (element instanceof FunctionBreakpoint) {
|
||||
this.debugService.removeFunctionBreakpoints(element.getId());
|
||||
await this.debugService.removeFunctionBreakpoints(element.getId());
|
||||
} else if (element instanceof DataBreakpoint) {
|
||||
await this.debugService.removeDataBreakpoints(element.getId());
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -222,14 +225,14 @@ export class BreakpointsView extends ViewletPanel {
|
||||
|
||||
private get elements(): IEnablement[] {
|
||||
const model = this.debugService.getModel();
|
||||
const elements = (<ReadonlyArray<IEnablement>>model.getExceptionBreakpoints()).concat(model.getFunctionBreakpoints()).concat(model.getBreakpoints());
|
||||
const elements = (<ReadonlyArray<IEnablement>>model.getExceptionBreakpoints()).concat(model.getFunctionBreakpoints()).concat(model.getDataBreakpoints()).concat(model.getBreakpoints());
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
private getExpandedBodySize(): number {
|
||||
const model = this.debugService.getModel();
|
||||
const length = model.getBreakpoints().length + model.getExceptionBreakpoints().length + model.getFunctionBreakpoints().length;
|
||||
const length = model.getBreakpoints().length + model.getExceptionBreakpoints().length + model.getFunctionBreakpoints().length + model.getDataBreakpoints().length;
|
||||
return Math.min(BreakpointsView.MAX_VISIBLE_FILES, length) * 22;
|
||||
}
|
||||
}
|
||||
@@ -259,6 +262,9 @@ class BreakpointsDelegate implements IListVirtualDelegate<IEnablement> {
|
||||
if (element instanceof ExceptionBreakpoint) {
|
||||
return ExceptionBreakpointsRenderer.ID;
|
||||
}
|
||||
if (element instanceof DataBreakpoint) {
|
||||
return DataBreakpointsRenderer.ID;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
@@ -454,6 +460,61 @@ class FunctionBreakpointsRenderer implements IListRenderer<FunctionBreakpoint, I
|
||||
}
|
||||
}
|
||||
|
||||
class DataBreakpointsRenderer implements IListRenderer<DataBreakpoint, IBaseBreakpointWithIconTemplateData> {
|
||||
|
||||
constructor(
|
||||
@IDebugService private readonly debugService: IDebugService
|
||||
) {
|
||||
// noop
|
||||
}
|
||||
|
||||
static readonly ID = 'databreakpoints';
|
||||
|
||||
get templateId() {
|
||||
return DataBreakpointsRenderer.ID;
|
||||
}
|
||||
|
||||
renderTemplate(container: HTMLElement): IBaseBreakpointWithIconTemplateData {
|
||||
const data: IBreakpointTemplateData = Object.create(null);
|
||||
data.breakpoint = dom.append(container, $('.breakpoint'));
|
||||
|
||||
data.icon = $('.icon');
|
||||
data.checkbox = createCheckbox();
|
||||
data.toDispose = [];
|
||||
data.toDispose.push(dom.addStandardDisposableListener(data.checkbox, 'change', (e) => {
|
||||
this.debugService.enableOrDisableBreakpoints(!data.context.enabled, data.context);
|
||||
}));
|
||||
|
||||
dom.append(data.breakpoint, data.icon);
|
||||
dom.append(data.breakpoint, data.checkbox);
|
||||
|
||||
data.name = dom.append(data.breakpoint, $('span.name'));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
renderElement(dataBreakpoint: DataBreakpoint, index: number, data: IBaseBreakpointWithIconTemplateData): void {
|
||||
data.context = dataBreakpoint;
|
||||
data.name.textContent = dataBreakpoint.label;
|
||||
const { className, message } = getBreakpointMessageAndClassName(this.debugService, dataBreakpoint);
|
||||
data.icon.className = className + ' icon';
|
||||
data.icon.title = message ? message : '';
|
||||
data.checkbox.checked = dataBreakpoint.enabled;
|
||||
data.breakpoint.title = dataBreakpoint.label;
|
||||
|
||||
// Mark function breakpoints as disabled if deactivated or if debug type does not support them #9099
|
||||
const session = this.debugService.getViewModel().focusedSession;
|
||||
dom.toggleClass(data.breakpoint, 'disabled', (session && !session.capabilities.supportsDataBreakpoints) || !this.debugService.getModel().areBreakpointsActivated());
|
||||
if (session && !session.capabilities.supportsDataBreakpoints) {
|
||||
data.breakpoint.title = nls.localize('dataBreakpointsNotSupported', "Data breakpoints are not supported by this debug type");
|
||||
}
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: IBaseBreakpointWithIconTemplateData): void {
|
||||
dispose(templateData.toDispose);
|
||||
}
|
||||
}
|
||||
|
||||
class FunctionBreakpointInputRenderer implements IListRenderer<IFunctionBreakpoint, IInputTemplateData> {
|
||||
|
||||
constructor(
|
||||
@@ -572,7 +633,7 @@ export function openBreakpointSource(breakpoint: IBreakpoint, sideBySide: boolea
|
||||
}, sideBySide ? SIDE_GROUP : ACTIVE_GROUP);
|
||||
}
|
||||
|
||||
export function getBreakpointMessageAndClassName(debugService: IDebugService, breakpoint: IBreakpoint | FunctionBreakpoint): { message?: string, className: string } {
|
||||
export function getBreakpointMessageAndClassName(debugService: IDebugService, breakpoint: IBreakpoint | FunctionBreakpoint | DataBreakpoint): { message?: string, className: string } {
|
||||
const state = debugService.state;
|
||||
const debugActive = state === State.Running || state === State.Stopped;
|
||||
|
||||
@@ -584,7 +645,7 @@ export function getBreakpointMessageAndClassName(debugService: IDebugService, br
|
||||
}
|
||||
|
||||
const appendMessage = (text: string): string => {
|
||||
return !(breakpoint instanceof FunctionBreakpoint) && breakpoint.message ? text.concat(', ' + breakpoint.message) : text;
|
||||
return !(breakpoint instanceof FunctionBreakpoint) && !(breakpoint instanceof DataBreakpoint) && breakpoint.message ? text.concat(', ' + breakpoint.message) : text;
|
||||
};
|
||||
if (debugActive && !breakpoint.verified) {
|
||||
return {
|
||||
@@ -607,6 +668,19 @@ export function getBreakpointMessageAndClassName(debugService: IDebugService, br
|
||||
};
|
||||
}
|
||||
|
||||
if (breakpoint instanceof DataBreakpoint) {
|
||||
if (session && !session.capabilities.supportsDataBreakpoints) {
|
||||
return {
|
||||
className: 'debug-data-breakpoint-unverified',
|
||||
message: nls.localize('dataBreakpointUnsupported', "Data breakpoints not supported by this debug type"),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
className: 'debug-data-breakpoint',
|
||||
};
|
||||
}
|
||||
|
||||
if (breakpoint.logMessage || breakpoint.condition || breakpoint.hitCondition) {
|
||||
const messages: string[] = [];
|
||||
if (breakpoint.logMessage) {
|
||||
|
||||
@@ -9,7 +9,7 @@ import * as lifecycle from 'vs/base/common/lifecycle';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { IDebugService, State, IEnablement, IBreakpoint, IDebugSession } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { Variable, Breakpoint } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { Variable, Breakpoint, FunctionBreakpoint } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
@@ -191,7 +191,7 @@ export class RemoveBreakpointAction extends AbstractDebugAction {
|
||||
|
||||
public run(breakpoint: IBreakpoint): Promise<any> {
|
||||
return breakpoint instanceof Breakpoint ? this.debugService.removeBreakpoints(breakpoint.getId())
|
||||
: this.debugService.removeFunctionBreakpoints(breakpoint.getId());
|
||||
: breakpoint instanceof FunctionBreakpoint ? this.debugService.removeFunctionBreakpoints(breakpoint.getId()) : this.debugService.removeDataBreakpoints(breakpoint.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ export class RemoveAllBreakpointsAction extends AbstractDebugAction {
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
return Promise.all([this.debugService.removeBreakpoints(), this.debugService.removeFunctionBreakpoints()]);
|
||||
return Promise.all([this.debugService.removeBreakpoints(), this.debugService.removeFunctionBreakpoints(), this.debugService.removeDataBreakpoints()]);
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
|
||||
@@ -10,7 +10,7 @@ import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/co
|
||||
import { IListService } from 'vs/platform/list/browser/listService';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { IDebugService, IEnablement, CONTEXT_BREAKPOINTS_FOCUSED, CONTEXT_WATCH_EXPRESSIONS_FOCUSED, CONTEXT_VARIABLES_FOCUSED, EDITOR_CONTRIBUTION_ID, IDebugEditorContribution, CONTEXT_IN_DEBUG_MODE, CONTEXT_EXPRESSION_SELECTED, CONTEXT_BREAKPOINT_SELECTED, IConfig, IStackFrame, IThread, IDebugSession, CONTEXT_DEBUG_STATE, REPL_ID, IDebugConfiguration, CONTEXT_JUMP_TO_CURSOR_SUPPORTED } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { Expression, Variable, Breakpoint, FunctionBreakpoint, Thread } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { Expression, Variable, Breakpoint, FunctionBreakpoint, Thread, DataBreakpoint } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { IExtensionsViewlet, VIEWLET_ID as EXTENSIONS_VIEWLET_ID } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { ICodeEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
@@ -410,6 +410,8 @@ export function registerCommands(): void {
|
||||
debugService.removeBreakpoints(element.getId());
|
||||
} else if (element instanceof FunctionBreakpoint) {
|
||||
debugService.removeFunctionBreakpoints(element.getId());
|
||||
} else if (element instanceof DataBreakpoint) {
|
||||
debugService.removeDataBreakpoints(element.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { FileChangesEvent, FileChangeType, IFileService } from 'vs/platform/files/common/files';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { DebugModel, ExceptionBreakpoint, FunctionBreakpoint, Breakpoint, Expression } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { DebugModel, ExceptionBreakpoint, FunctionBreakpoint, Breakpoint, Expression, DataBreakpoint } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { ViewModel } from 'vs/workbench/contrib/debug/common/debugViewModel';
|
||||
import * as debugactions from 'vs/workbench/contrib/debug/browser/debugActions';
|
||||
import { ConfigurationManager } from 'vs/workbench/contrib/debug/browser/debugConfigurationManager';
|
||||
@@ -52,6 +52,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
const DEBUG_BREAKPOINTS_KEY = 'debug.breakpoint';
|
||||
const DEBUG_BREAKPOINTS_ACTIVATED_KEY = 'debug.breakpointactivated';
|
||||
const DEBUG_FUNCTION_BREAKPOINTS_KEY = 'debug.functionbreakpoint';
|
||||
const DEBUG_DATA_BREAKPOINTS_KEY = 'debug.databreakpoint';
|
||||
const DEBUG_EXCEPTION_BREAKPOINTS_KEY = 'debug.exceptionbreakpoint';
|
||||
const DEBUG_WATCH_EXPRESSIONS_KEY = 'debug.watchexpressions';
|
||||
|
||||
@@ -129,7 +130,7 @@ export class DebugService implements IDebugService {
|
||||
this.inDebugMode = CONTEXT_IN_DEBUG_MODE.bindTo(contextKeyService);
|
||||
|
||||
this.model = new DebugModel(this.loadBreakpoints(), this.storageService.getBoolean(DEBUG_BREAKPOINTS_ACTIVATED_KEY, StorageScope.WORKSPACE, true), this.loadFunctionBreakpoints(),
|
||||
this.loadExceptionBreakpoints(), this.loadWatchExpressions(), this.textFileService);
|
||||
this.loadExceptionBreakpoints(), this.loadDataBreakpoints(), this.loadWatchExpressions(), this.textFileService);
|
||||
this.toDispose.push(this.model);
|
||||
|
||||
this.viewModel = new ViewModel(contextKeyService);
|
||||
@@ -851,6 +852,8 @@ export class DebugService implements IDebugService {
|
||||
await this.sendBreakpoints(breakpoint.uri);
|
||||
} else if (breakpoint instanceof FunctionBreakpoint) {
|
||||
await this.sendFunctionBreakpoints();
|
||||
} else if (breakpoint instanceof DataBreakpoint) {
|
||||
await this.sendDataBreakpoints();
|
||||
} else {
|
||||
await this.sendExceptionBreakpoints();
|
||||
}
|
||||
@@ -920,6 +923,19 @@ export class DebugService implements IDebugService {
|
||||
this.storeBreakpoints();
|
||||
}
|
||||
|
||||
async addDataBreakpoint(label: string, dataId: string, canPersist: boolean): Promise<void> {
|
||||
this.model.addDataBreakpoint(label, dataId, canPersist);
|
||||
await this.sendDataBreakpoints();
|
||||
|
||||
this.storeBreakpoints();
|
||||
}
|
||||
|
||||
async removeDataBreakpoints(id?: string): Promise<void> {
|
||||
this.model.removeDataBreakpoints(id);
|
||||
await this.sendDataBreakpoints();
|
||||
this.storeBreakpoints();
|
||||
}
|
||||
|
||||
sendAllBreakpoints(session?: IDebugSession): Promise<any> {
|
||||
return Promise.all(distinct(this.model.getBreakpoints(), bp => bp.uri.toString()).map(bp => this.sendBreakpoints(bp.uri, false, session)))
|
||||
.then(() => this.sendFunctionBreakpoints(session))
|
||||
@@ -943,6 +959,14 @@ export class DebugService implements IDebugService {
|
||||
});
|
||||
}
|
||||
|
||||
private sendDataBreakpoints(session?: IDebugSession): Promise<void> {
|
||||
const breakpointsToSend = this.model.getDataBreakpoints().filter(fbp => fbp.enabled && this.model.areBreakpointsActivated());
|
||||
|
||||
return this.sendToOneOrAllSessions(session, s => {
|
||||
return s.capabilities.supportsDataBreakpoints ? s.sendDataBreakpoints(breakpointsToSend) : Promise.resolve(undefined);
|
||||
});
|
||||
}
|
||||
|
||||
private sendExceptionBreakpoints(session?: IDebugSession): Promise<void> {
|
||||
const enabledExceptionBps = this.model.getExceptionBreakpoints().filter(exb => exb.enabled);
|
||||
|
||||
@@ -1006,6 +1030,17 @@ export class DebugService implements IDebugService {
|
||||
return result || [];
|
||||
}
|
||||
|
||||
private loadDataBreakpoints(): DataBreakpoint[] {
|
||||
let result: DataBreakpoint[] | undefined;
|
||||
try {
|
||||
result = JSON.parse(this.storageService.get(DEBUG_DATA_BREAKPOINTS_KEY, StorageScope.WORKSPACE, '[]')).map((dbp: any) => {
|
||||
return new DataBreakpoint(dbp.label, dbp.dataId, true, dbp.enabled, dbp.hitCondition, dbp.condition, dbp.logMessage);
|
||||
});
|
||||
} catch (e) { }
|
||||
|
||||
return result || [];
|
||||
}
|
||||
|
||||
private loadWatchExpressions(): Expression[] {
|
||||
let result: Expression[] | undefined;
|
||||
try {
|
||||
@@ -1041,6 +1076,13 @@ export class DebugService implements IDebugService {
|
||||
this.storageService.remove(DEBUG_FUNCTION_BREAKPOINTS_KEY, StorageScope.WORKSPACE);
|
||||
}
|
||||
|
||||
const dataBreakpoints = this.model.getDataBreakpoints().filter(dbp => dbp.canPersist);
|
||||
if (dataBreakpoints.length) {
|
||||
this.storageService.store(DEBUG_DATA_BREAKPOINTS_KEY, JSON.stringify(dataBreakpoints), StorageScope.WORKSPACE);
|
||||
} else {
|
||||
this.storageService.remove(DEBUG_DATA_BREAKPOINTS_KEY, StorageScope.WORKSPACE);
|
||||
}
|
||||
|
||||
const exceptionBreakpoints = this.model.getExceptionBreakpoints();
|
||||
if (exceptionBreakpoints.length) {
|
||||
this.storageService.store(DEBUG_EXCEPTION_BREAKPOINTS_KEY, JSON.stringify(exceptionBreakpoints), StorageScope.WORKSPACE);
|
||||
|
||||
@@ -12,7 +12,7 @@ import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { CompletionItem, completionKindFromString } 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, IBreakpoint, IExceptionInfo, AdapterEndEvent, IDebugger, VIEWLET_ID, IDebugConfiguration, IReplElement, IStackFrame, IExpression, IReplElementSource } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IDebugSession, IConfig, IThread, IRawModelUpdate, IDebugService, IRawStoppedDetails, State, LoadedSourceEvent, IFunctionBreakpoint, IExceptionBreakpoint, IBreakpoint, IExceptionInfo, AdapterEndEvent, IDebugger, VIEWLET_ID, IDebugConfiguration, IReplElement, IStackFrame, IExpression, IReplElementSource, IDataBreakpoint } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
import { Thread, ExpressionContainer, DebugModel } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
@@ -327,6 +327,34 @@ export class DebugSession implements IDebugSession {
|
||||
return Promise.reject(new Error('no debug adapter'));
|
||||
}
|
||||
|
||||
dataBreakpointInfo(name: string, variablesReference?: number): Promise<{ dataId: string | null, description: string, canPersist?: boolean }> {
|
||||
if (this.raw) {
|
||||
if (this.raw.readyForBreakpoints) {
|
||||
return this.raw.dataBreakpointInfo({ name, variablesReference }).then(response => response.body);
|
||||
}
|
||||
return Promise.reject(new Error(nls.localize('sessionNotReadyForBreakpoints', "Session is not ready for breakpoints")));
|
||||
}
|
||||
return Promise.reject(new Error('no debug adapter'));
|
||||
}
|
||||
|
||||
sendDataBreakpoints(dataBreakpoints: IDataBreakpoint[]): Promise<void> {
|
||||
if (this.raw) {
|
||||
if (this.raw.readyForBreakpoints) {
|
||||
return this.raw.setDataBreakpoints({ breakpoints: dataBreakpoints }).then(response => {
|
||||
if (response && response.body) {
|
||||
const data = new Map<string, DebugProtocol.Breakpoint>();
|
||||
for (let i = 0; i < dataBreakpoints.length; i++) {
|
||||
data.set(dataBreakpoints[i].getId(), response.body.breakpoints[i]);
|
||||
}
|
||||
this.model.setBreakpointSessionData(this.getId(), data);
|
||||
}
|
||||
});
|
||||
}
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
return Promise.reject(new Error('no debug adapter'));
|
||||
}
|
||||
|
||||
customRequest(request: string, args: any): Promise<DebugProtocol.Response> {
|
||||
if (this.raw) {
|
||||
return this.raw.custom(request, args);
|
||||
|
||||
@@ -357,6 +357,20 @@ export class RawDebugSession {
|
||||
return Promise.reject(new Error('setFunctionBreakpoints not supported'));
|
||||
}
|
||||
|
||||
dataBreakpointInfo(args: DebugProtocol.DataBreakpointInfoArguments): Promise<DebugProtocol.DataBreakpointInfoResponse> {
|
||||
if (this.capabilities.supportsDataBreakpoints) {
|
||||
return this.send<DebugProtocol.DataBreakpointInfoResponse>('dataBreakpointInfo', args);
|
||||
}
|
||||
return Promise.reject(new Error('dataBreakpointInfo not supported'));
|
||||
}
|
||||
|
||||
setDataBreakpoints(args: DebugProtocol.SetDataBreakpointsArguments): Promise<DebugProtocol.SetDataBreakpointsResponse> {
|
||||
if (this.capabilities.supportsDataBreakpoints) {
|
||||
return this.send<DebugProtocol.SetDataBreakpointsResponse>('setDataBreakpoints', args);
|
||||
}
|
||||
return Promise.reject(new Error('setDataBreakpoints not supported'));
|
||||
}
|
||||
|
||||
setExceptionBreakpoints(args: DebugProtocol.SetExceptionBreakpointsArguments): Promise<DebugProtocol.SetExceptionBreakpointsResponse> {
|
||||
return this.send<DebugProtocol.SetExceptionBreakpointsResponse>('setExceptionBreakpoints', args);
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ export class VariablesView extends ViewletPanel {
|
||||
this.tree.updateChildren();
|
||||
}));
|
||||
this._register(this.tree.onMouseDblClick(e => this.onMouseDblClick(e)));
|
||||
this._register(this.tree.onContextMenu(e => this.onContextMenu(e)));
|
||||
this._register(this.tree.onContextMenu(async e => await this.onContextMenu(e)));
|
||||
|
||||
this._register(this.onDidChangeBodyVisibility(visible => {
|
||||
if (visible && this.needsRefresh) {
|
||||
@@ -152,7 +152,7 @@ export class VariablesView extends ViewletPanel {
|
||||
}
|
||||
}
|
||||
|
||||
private onContextMenu(e: ITreeContextMenuEvent<IExpression | IScope>): void {
|
||||
private async onContextMenu(e: ITreeContextMenuEvent<IExpression | IScope>): Promise<void> {
|
||||
const variable = e.element;
|
||||
if (variable instanceof Variable && !!variable.value) {
|
||||
const actions: IAction[] = [];
|
||||
@@ -174,6 +174,16 @@ export class VariablesView extends ViewletPanel {
|
||||
return Promise.resolve(undefined);
|
||||
}));
|
||||
}
|
||||
if (session && session.capabilities.supportsDataBreakpoints) {
|
||||
const response = await session.dataBreakpointInfo(variable.name, variable.parent.reference);
|
||||
const dataid = response.dataId;
|
||||
if (dataid) {
|
||||
actions.push(new Separator());
|
||||
actions.push(new Action('debug.addDataBreakpoint', nls.localize('setDataBreakpoint', "Set Data Breakpoint"), undefined, true, () => {
|
||||
return this.debugService.addDataBreakpoint(response.description, dataid, !!response.canPersist);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => e.anchor,
|
||||
|
||||
@@ -103,6 +103,7 @@ export interface IReplElementSource {
|
||||
export interface IExpressionContainer extends ITreeElement {
|
||||
readonly hasChildren: boolean;
|
||||
getChildren(): Promise<IExpression[]>;
|
||||
readonly reference?: number;
|
||||
}
|
||||
|
||||
export interface IExpression extends IReplElement, IExpressionContainer {
|
||||
@@ -201,6 +202,8 @@ export interface IDebugSession extends ITreeElement {
|
||||
|
||||
sendBreakpoints(modelUri: uri, bpts: IBreakpoint[], sourceModified: boolean): Promise<void>;
|
||||
sendFunctionBreakpoints(fbps: IFunctionBreakpoint[]): Promise<void>;
|
||||
dataBreakpointInfo(name: string, variablesReference?: number): Promise<{ dataId: string | null, description: string, canPersist?: boolean }>;
|
||||
sendDataBreakpoints(dbps: IDataBreakpoint[]): Promise<void>;
|
||||
sendExceptionBreakpoints(exbpts: IExceptionBreakpoint[]): Promise<void>;
|
||||
|
||||
stackTrace(threadId: number, startFrame: number, levels: number): Promise<DebugProtocol.StackTraceResponse>;
|
||||
@@ -357,6 +360,12 @@ export interface IExceptionBreakpoint extends IEnablement {
|
||||
readonly label: string;
|
||||
}
|
||||
|
||||
export interface IDataBreakpoint extends IBaseBreakpoint {
|
||||
readonly label: string;
|
||||
readonly dataId: string;
|
||||
readonly canPersist: boolean;
|
||||
}
|
||||
|
||||
export interface IExceptionInfo {
|
||||
readonly id?: string;
|
||||
readonly description?: string;
|
||||
@@ -404,6 +413,7 @@ export interface IDebugModel extends ITreeElement {
|
||||
getBreakpoints(filter?: { uri?: uri, lineNumber?: number, column?: number, enabledOnly?: boolean }): ReadonlyArray<IBreakpoint>;
|
||||
areBreakpointsActivated(): boolean;
|
||||
getFunctionBreakpoints(): ReadonlyArray<IFunctionBreakpoint>;
|
||||
getDataBreakpoints(): ReadonlyArray<IDataBreakpoint>;
|
||||
getExceptionBreakpoints(): ReadonlyArray<IExceptionBreakpoint>;
|
||||
getWatchExpressions(): ReadonlyArray<IExpression & IEvaluate>;
|
||||
|
||||
@@ -416,9 +426,9 @@ export interface IDebugModel extends ITreeElement {
|
||||
* An event describing a change to the set of [breakpoints](#debug.Breakpoint).
|
||||
*/
|
||||
export interface IBreakpointsChangeEvent {
|
||||
added?: Array<IBreakpoint | IFunctionBreakpoint>;
|
||||
removed?: Array<IBreakpoint | IFunctionBreakpoint>;
|
||||
changed?: Array<IBreakpoint | IFunctionBreakpoint>;
|
||||
added?: Array<IBreakpoint | IFunctionBreakpoint | IDataBreakpoint>;
|
||||
removed?: Array<IBreakpoint | IFunctionBreakpoint | IDataBreakpoint>;
|
||||
changed?: Array<IBreakpoint | IFunctionBreakpoint | IDataBreakpoint>;
|
||||
sessionOnly?: boolean;
|
||||
}
|
||||
|
||||
@@ -754,6 +764,17 @@ export interface IDebugService {
|
||||
*/
|
||||
removeFunctionBreakpoints(id?: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* Adds a new data breakpoint.
|
||||
*/
|
||||
addDataBreakpoint(label: string, dataId: string, canPersist: boolean): Promise<void>;
|
||||
|
||||
/**
|
||||
* Removes all data breakpoints. If id is passed only removes the data breakpoint with the passed id.
|
||||
* Notifies debug adapter of breakpoint changes.
|
||||
*/
|
||||
removeDataBreakpoints(id?: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* Sends all breakpoints to the passed session.
|
||||
* If session is not passed, sends all breakpoints to each session.
|
||||
|
||||
@@ -16,7 +16,7 @@ import { distinct, lastIndex } from 'vs/base/common/arrays';
|
||||
import { Range, IRange } from 'vs/editor/common/core/range';
|
||||
import {
|
||||
ITreeElement, IExpression, IExpressionContainer, IDebugSession, IStackFrame, IExceptionBreakpoint, IBreakpoint, IFunctionBreakpoint, IDebugModel, IReplElementSource,
|
||||
IThread, IRawModelUpdate, IScope, IRawStoppedDetails, IEnablement, IBreakpointData, IExceptionInfo, IReplElement, IBreakpointsChangeEvent, IBreakpointUpdateData, IBaseBreakpoint, State
|
||||
IThread, IRawModelUpdate, IScope, IRawStoppedDetails, IEnablement, IBreakpointData, IExceptionInfo, IReplElement, IBreakpointsChangeEvent, IBreakpointUpdateData, IBaseBreakpoint, State, IDataBreakpoint
|
||||
} from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { Source, UNKNOWN_SOURCE_LABEL } from 'vs/workbench/contrib/debug/common/debugSource';
|
||||
import { commonSuffixLength } from 'vs/base/common/strings';
|
||||
@@ -735,6 +735,34 @@ export class FunctionBreakpoint extends BaseBreakpoint implements IFunctionBreak
|
||||
}
|
||||
}
|
||||
|
||||
export class DataBreakpoint extends BaseBreakpoint implements IDataBreakpoint {
|
||||
|
||||
constructor(
|
||||
public label: string,
|
||||
public dataId: string,
|
||||
public canPersist: boolean,
|
||||
enabled: boolean,
|
||||
hitCondition: string | undefined,
|
||||
condition: string | undefined,
|
||||
logMessage: string | undefined,
|
||||
id = generateUuid()
|
||||
) {
|
||||
super(enabled, hitCondition, condition, logMessage, id);
|
||||
}
|
||||
|
||||
toJSON(): any {
|
||||
const result = super.toJSON();
|
||||
result.label = this.label;
|
||||
result.dataid = this.dataId;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return this.label;
|
||||
}
|
||||
}
|
||||
|
||||
export class ExceptionBreakpoint extends Enablement implements IExceptionBreakpoint {
|
||||
|
||||
constructor(public filter: string, public label: string, enabled: boolean) {
|
||||
@@ -778,6 +806,7 @@ export class DebugModel implements IDebugModel {
|
||||
private breakpointsActivated: boolean,
|
||||
private functionBreakpoints: FunctionBreakpoint[],
|
||||
private exceptionBreakpoints: ExceptionBreakpoint[],
|
||||
private dataBreakopints: DataBreakpoint[],
|
||||
private watchExpressions: Expression[],
|
||||
private textFileService: ITextFileService
|
||||
) {
|
||||
@@ -918,6 +947,10 @@ export class DebugModel implements IDebugModel {
|
||||
return this.functionBreakpoints;
|
||||
}
|
||||
|
||||
getDataBreakpoints(): IDataBreakpoint[] {
|
||||
return this.dataBreakopints;
|
||||
}
|
||||
|
||||
getExceptionBreakpoints(): IExceptionBreakpoint[] {
|
||||
return this.exceptionBreakpoints;
|
||||
}
|
||||
@@ -991,6 +1024,12 @@ export class DebugModel implements IDebugModel {
|
||||
fbp.setSessionData(sessionId, fbpData);
|
||||
}
|
||||
});
|
||||
this.dataBreakopints.forEach(dbp => {
|
||||
const dbpData = data.get(dbp.getId());
|
||||
if (dbpData) {
|
||||
dbp.setSessionData(sessionId, dbpData);
|
||||
}
|
||||
});
|
||||
|
||||
this._onDidChangeBreakpoints.fire({
|
||||
sessionOnly: true
|
||||
@@ -1001,6 +1040,7 @@ export class DebugModel implements IDebugModel {
|
||||
this.breakpointsSessionId = sessionId;
|
||||
this.breakpoints.forEach(bp => bp.setSessionId(sessionId));
|
||||
this.functionBreakpoints.forEach(fbp => fbp.setSessionId(sessionId));
|
||||
this.dataBreakopints.forEach(dbp => dbp.setSessionId(sessionId));
|
||||
|
||||
this._onDidChangeBreakpoints.fire({
|
||||
sessionOnly: true
|
||||
@@ -1038,7 +1078,7 @@ export class DebugModel implements IDebugModel {
|
||||
}
|
||||
|
||||
enableOrDisableAllBreakpoints(enable: boolean): void {
|
||||
const changed: Array<IBreakpoint | IFunctionBreakpoint> = [];
|
||||
const changed: Array<IBreakpoint | IFunctionBreakpoint | IDataBreakpoint> = [];
|
||||
|
||||
this.breakpoints.forEach(bp => {
|
||||
if (bp.enabled !== enable) {
|
||||
@@ -1052,6 +1092,12 @@ export class DebugModel implements IDebugModel {
|
||||
}
|
||||
fbp.enabled = enable;
|
||||
});
|
||||
this.dataBreakopints.forEach(dbp => {
|
||||
if (dbp.enabled !== enable) {
|
||||
changed.push(dbp);
|
||||
}
|
||||
dbp.enabled = enable;
|
||||
});
|
||||
|
||||
this._onDidChangeBreakpoints.fire({ changed: changed });
|
||||
}
|
||||
@@ -1073,7 +1119,6 @@ export class DebugModel implements IDebugModel {
|
||||
}
|
||||
|
||||
removeFunctionBreakpoints(id?: string): void {
|
||||
|
||||
let removed: FunctionBreakpoint[];
|
||||
if (id) {
|
||||
removed = this.functionBreakpoints.filter(fbp => fbp.getId() === id);
|
||||
@@ -1082,7 +1127,25 @@ export class DebugModel implements IDebugModel {
|
||||
removed = this.functionBreakpoints;
|
||||
this.functionBreakpoints = [];
|
||||
}
|
||||
this._onDidChangeBreakpoints.fire({ removed: removed });
|
||||
this._onDidChangeBreakpoints.fire({ removed });
|
||||
}
|
||||
|
||||
addDataBreakpoint(label: string, dataId: string, canPersist: boolean): void {
|
||||
const newDataBreakpoint = new DataBreakpoint(label, dataId, canPersist, true, undefined, undefined, undefined);
|
||||
this.dataBreakopints.push(newDataBreakpoint);
|
||||
this._onDidChangeBreakpoints.fire({ added: [newDataBreakpoint] });
|
||||
}
|
||||
|
||||
removeDataBreakpoints(id?: string): void {
|
||||
let removed: DataBreakpoint[];
|
||||
if (id) {
|
||||
removed = this.dataBreakopints.filter(fbp => fbp.getId() === id);
|
||||
this.dataBreakopints = this.dataBreakopints.filter(fbp => fbp.getId() !== id);
|
||||
} else {
|
||||
removed = this.dataBreakopints;
|
||||
this.dataBreakopints = [];
|
||||
}
|
||||
this._onDidChangeBreakpoints.fire({ removed });
|
||||
}
|
||||
|
||||
getWatchExpressions(): Expression[] {
|
||||
|
||||
@@ -23,7 +23,7 @@ suite('Debug - Model', () => {
|
||||
let rawSession: MockRawSession;
|
||||
|
||||
setup(() => {
|
||||
model = new DebugModel([], true, [], [], [], <any>{ isDirty: (e: any) => false });
|
||||
model = new DebugModel([], true, [], [], [], [], <any>{ isDirty: (e: any) => false });
|
||||
rawSession = new MockRawSession();
|
||||
});
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { URI as uri } from 'vs/base/common/uri';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
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, IFunctionBreakpoint, IExceptionBreakpoint, IDebugger, IExceptionInfo, AdapterEndEvent, IReplElement, IExpression, IReplElementSource } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { ILaunch, IDebugService, State, IDebugSession, IConfigurationManager, IStackFrame, IBreakpointData, IBreakpointUpdateData, IConfig, IDebugModel, IViewModel, IBreakpoint, LoadedSourceEvent, IThread, IRawModelUpdate, IFunctionBreakpoint, IExceptionBreakpoint, IDebugger, IExceptionInfo, AdapterEndEvent, IReplElement, IExpression, IReplElementSource, IDataBreakpoint } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
|
||||
import { CompletionItem } from 'vs/editor/common/modes';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
@@ -79,6 +79,13 @@ export class MockDebugService implements IDebugService {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
|
||||
addDataBreakpoint(label: string, dataId: string, canPersist: boolean): Promise<void> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
removeDataBreakpoints(id?: string | undefined): Promise<void> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
public addReplExpression(name: string): Promise<void> {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
@@ -125,6 +132,13 @@ export class MockDebugService implements IDebugService {
|
||||
}
|
||||
|
||||
export class MockSession implements IDebugSession {
|
||||
dataBreakpointInfo(name: string, variablesReference?: number | undefined): Promise<{ dataId: string | null; description: string; canPersist?: boolean | undefined; }> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
sendDataBreakpoints(dbps: IDataBreakpoint[]): Promise<void> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
subId: string | undefined;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user