Skip to content

Commit

Permalink
breakpoints: inline action to edit condition. Render conditions for f…
Browse files Browse the repository at this point in the history
…unction breakpoints. Allow to edit conditions for function breakpoints

fixes #113805
fixes #3646
  • Loading branch information
isidorn committed Jan 14, 2021
1 parent e9f6c35 commit 7a9bb5a
Show file tree
Hide file tree
Showing 9 changed files with 282 additions and 185 deletions.
289 changes: 200 additions & 89 deletions src/vs/workbench/contrib/debug/browser/breakpointsView.ts

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/vs/workbench/contrib/debug/browser/debugCommands.ts
Expand Up @@ -9,7 +9,7 @@ import { List } from 'vs/base/browser/ui/list/listWidget';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
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, IDebugConfiguration, CONTEXT_JUMP_TO_CURSOR_SUPPORTED, REPL_VIEW_ID, CONTEXT_DEBUGGERS_AVAILABLE, State, getStateLabel } from 'vs/workbench/contrib/debug/common/debug';
import { IDebugService, IEnablement, CONTEXT_BREAKPOINTS_FOCUSED, CONTEXT_WATCH_EXPRESSIONS_FOCUSED, CONTEXT_VARIABLES_FOCUSED, EDITOR_CONTRIBUTION_ID, IDebugEditorContribution, CONTEXT_IN_DEBUG_MODE, CONTEXT_EXPRESSION_SELECTED, IConfig, IStackFrame, IThread, IDebugSession, CONTEXT_DEBUG_STATE, IDebugConfiguration, CONTEXT_JUMP_TO_CURSOR_SUPPORTED, REPL_VIEW_ID, CONTEXT_DEBUGGERS_AVAILABLE, State, getStateLabel, CONTEXT_BREAKPOINT_INPUT_FOCUSED } from 'vs/workbench/contrib/debug/common/debug';
import { Expression, Variable, Breakpoint, FunctionBreakpoint, DataBreakpoint } from 'vs/workbench/contrib/debug/common/debugModel';
import { IExtensionsViewPaneContainer, VIEWLET_ID as EXTENSIONS_VIEWLET_ID } from 'vs/workbench/contrib/extensions/common/extensions';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
Expand Down Expand Up @@ -525,7 +525,7 @@ export function registerCommands(): void {
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'debug.removeBreakpoint',
weight: KeybindingWeight.WorkbenchContrib,
when: ContextKeyExpr.and(CONTEXT_BREAKPOINTS_FOCUSED, CONTEXT_BREAKPOINT_SELECTED.toNegated()),
when: ContextKeyExpr.and(CONTEXT_BREAKPOINTS_FOCUSED, CONTEXT_BREAKPOINT_INPUT_FOCUSED.toNegated()),
primary: KeyCode.Delete,
mac: { primary: KeyMod.CtrlCmd | KeyCode.Backspace },
handler: (accessor) => {
Expand Down
7 changes: 3 additions & 4 deletions src/vs/workbench/contrib/debug/browser/debugService.ts
Expand Up @@ -900,12 +900,11 @@ export class DebugService implements IDebugService {
}

addFunctionBreakpoint(name?: string, id?: string): void {
const newFunctionBreakpoint = this.model.addFunctionBreakpoint(name || '', id);
this.viewModel.setSelectedBreakpoint(newFunctionBreakpoint);
this.model.addFunctionBreakpoint(name || '', id);
}

async renameFunctionBreakpoint(id: string, newFunctionName: string): Promise<void> {
this.model.renameFunctionBreakpoint(id, newFunctionName);
async updateFunctionBreakpoint(id: string, update: { name?: string, hitCondition?: string, condition?: string }): Promise<void> {
this.model.updateFunctionBreakpoint(id, update);
this.debugStorage.storeBreakpoints(this.model);
await this.sendFunctionBreakpoints();
}
Expand Down
Expand Up @@ -319,7 +319,7 @@
}

.debug-pane .debug-breakpoints .breakpoint > .file-path,
.debug-pane .debug-breakpoints .breakpoint.exception > .condition {
.debug-pane .debug-breakpoints .breakpoint > .condition {
opacity: 0.7;
margin-left: 0.9em;
flex: 1;
Expand Down
11 changes: 4 additions & 7 deletions src/vs/workbench/contrib/debug/common/debug.ts
Expand Up @@ -50,11 +50,11 @@ export const CONTEXT_WATCH_EXPRESSIONS_FOCUSED = new RawContextKey<boolean>('wat
export const CONTEXT_WATCH_EXPRESSIONS_EXIST = new RawContextKey<boolean>('watchExpressionsExist', false);
export const CONTEXT_VARIABLES_FOCUSED = new RawContextKey<boolean>('variablesFocused', true);
export const CONTEXT_EXPRESSION_SELECTED = new RawContextKey<boolean>('expressionSelected', false);
export const CONTEXT_BREAKPOINT_SELECTED = new RawContextKey<boolean>('breakpointSelected', false);
export const CONTEXT_BREAKPOINT_INPUT_FOCUSED = new RawContextKey<boolean>('breakpointInputFocused', false);
export const CONTEXT_CALLSTACK_ITEM_TYPE = new RawContextKey<string>('callStackItemType', undefined);
export const CONTEXT_WATCH_ITEM_TYPE = new RawContextKey<string>('watchItemType', undefined);
export const CONTEXT_BREAKPOINT_ITEM_TYPE = new RawContextKey<string>('breakpointItemType', undefined);
export const CONTEXT_EXCEPTION_BREAKPOINT_SUPPORTS_CONDITION = new RawContextKey<boolean>('exceptionBreakpointSupportsCondition', false);
export const CONTEXT_BREAKPOINT_SUPPORTS_CONDITION = new RawContextKey<boolean>('breakpointSupportsCondition', false);
export const CONTEXT_LOADED_SCRIPTS_SUPPORTED = new RawContextKey<boolean>('loadedScriptsSupported', false);
export const CONTEXT_LOADED_SCRIPTS_ITEM_TYPE = new RawContextKey<string>('loadedScriptsItemType', undefined);
export const CONTEXT_FOCUSED_SESSION_IS_ATTACH = new RawContextKey<boolean>('focusedSessionIsAttach', false);
Expand Down Expand Up @@ -444,17 +444,14 @@ export interface IViewModel extends ITreeElement {
readonly focusedStackFrame: IStackFrame | undefined;

getSelectedExpression(): IExpression | undefined;
getSelectedBreakpoint(): IFunctionBreakpoint | IExceptionBreakpoint | undefined;
setSelectedExpression(expression: IExpression | undefined): void;
setSelectedBreakpoint(functionBreakpoint: IFunctionBreakpoint | IExceptionBreakpoint | undefined): void;
updateViews(): void;

isMultiSessionView(): boolean;

onDidFocusSession: Event<IDebugSession | undefined>;
onDidFocusStackFrame: Event<{ stackFrame: IStackFrame | undefined, explicit: boolean }>;
onDidSelectExpression: Event<IExpression | undefined>;
onDidSelectBreakpoint: Event<IFunctionBreakpoint | IExceptionBreakpoint | undefined>;
onWillUpdateViews: Event<void>;
}

Expand Down Expand Up @@ -852,10 +849,10 @@ export interface IDebugService {
addFunctionBreakpoint(name?: string, id?: string): void;

/**
* Renames an already existing function breakpoint.
* Updates an already existing function breakpoint.
* Notifies debug adapter of breakpoint changes.
*/
renameFunctionBreakpoint(id: string, newFunctionName: string): Promise<void>;
updateFunctionBreakpoint(id: string, update: { name?: string, hitCondition?: string, condition?: string }): Promise<void>;

/**
* Removes all function breakpoints. If id is passed only removes the function breakpoint with the passed id.
Expand Down
12 changes: 10 additions & 2 deletions src/vs/workbench/contrib/debug/common/debugModel.ts
Expand Up @@ -1244,10 +1244,18 @@ export class DebugModel implements IDebugModel {
return newFunctionBreakpoint;
}

renameFunctionBreakpoint(id: string, name: string): void {
updateFunctionBreakpoint(id: string, update: { name?: string, hitCondition?: string, condition?: string }): void {
const functionBreakpoint = this.functionBreakpoints.find(fbp => fbp.getId() === id);
if (functionBreakpoint) {
functionBreakpoint.name = name;
if (typeof update.name === 'string') {
functionBreakpoint.name = update.name;
}
if (typeof update.condition === 'string') {
functionBreakpoint.condition = update.condition;
}
if (typeof update.hitCondition === 'string') {
functionBreakpoint.hitCondition = update.hitCondition;
}
this._onDidChangeBreakpoints.fire({ changed: [functionBreakpoint], sessionOnly: false });
}
}
Expand Down
20 changes: 1 addition & 19 deletions src/vs/workbench/contrib/debug/common/debugViewModel.ts
Expand Up @@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/

import { Event, Emitter } from 'vs/base/common/event';
import { CONTEXT_EXPRESSION_SELECTED, IViewModel, IStackFrame, IDebugSession, IThread, IExpression, IFunctionBreakpoint, CONTEXT_BREAKPOINT_SELECTED, CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_RESTART_FRAME_SUPPORTED, CONTEXT_JUMP_TO_CURSOR_SUPPORTED, CONTEXT_STEP_INTO_TARGETS_SUPPORTED, CONTEXT_SET_VARIABLE_SUPPORTED, IExceptionBreakpoint, CONTEXT_MULTI_SESSION_DEBUG } from 'vs/workbench/contrib/debug/common/debug';
import { CONTEXT_EXPRESSION_SELECTED, IViewModel, IStackFrame, IDebugSession, IThread, IExpression, CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_RESTART_FRAME_SUPPORTED, CONTEXT_JUMP_TO_CURSOR_SUPPORTED, CONTEXT_STEP_INTO_TARGETS_SUPPORTED, CONTEXT_SET_VARIABLE_SUPPORTED, CONTEXT_MULTI_SESSION_DEBUG } from 'vs/workbench/contrib/debug/common/debug';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { isSessionAttach } from 'vs/workbench/contrib/debug/common/debugUtils';

Expand All @@ -16,14 +16,11 @@ export class ViewModel implements IViewModel {
private _focusedSession: IDebugSession | undefined;
private _focusedThread: IThread | undefined;
private selectedExpression: IExpression | undefined;
private selectedBreakpoint: IFunctionBreakpoint | IExceptionBreakpoint | undefined;
private readonly _onDidFocusSession = new Emitter<IDebugSession | undefined>();
private readonly _onDidFocusStackFrame = new Emitter<{ stackFrame: IStackFrame | undefined, explicit: boolean }>();
private readonly _onDidSelectExpression = new Emitter<IExpression | undefined>();
private readonly _onDidSelectBreakpoint = new Emitter<IFunctionBreakpoint | IExceptionBreakpoint | undefined>();
private readonly _onWillUpdateViews = new Emitter<void>();
private expressionSelectedContextKey!: IContextKey<boolean>;
private breakpointSelectedContextKey!: IContextKey<boolean>;
private loadedScriptsSupportedContextKey!: IContextKey<boolean>;
private stepBackSupportedContextKey!: IContextKey<boolean>;
private focusedSessionIsAttach!: IContextKey<boolean>;
Expand All @@ -36,7 +33,6 @@ export class ViewModel implements IViewModel {
constructor(private contextKeyService: IContextKeyService) {
contextKeyService.bufferChangeEvents(() => {
this.expressionSelectedContextKey = CONTEXT_EXPRESSION_SELECTED.bindTo(contextKeyService);
this.breakpointSelectedContextKey = CONTEXT_BREAKPOINT_SELECTED.bindTo(contextKeyService);
this.loadedScriptsSupportedContextKey = CONTEXT_LOADED_SCRIPTS_SUPPORTED.bindTo(contextKeyService);
this.stepBackSupportedContextKey = CONTEXT_STEP_BACK_SUPPORTED.bindTo(contextKeyService);
this.focusedSessionIsAttach = CONTEXT_FOCUSED_SESSION_IS_ATTACH.bindTo(contextKeyService);
Expand Down Expand Up @@ -113,14 +109,6 @@ export class ViewModel implements IViewModel {
return this._onDidSelectExpression.event;
}

get onDidSelectBreakpoint(): Event<IFunctionBreakpoint | IExceptionBreakpoint | undefined> {
return this._onDidSelectBreakpoint.event;
}

getSelectedBreakpoint(): IFunctionBreakpoint | IExceptionBreakpoint | undefined {
return this.selectedBreakpoint;
}

updateViews(): void {
this._onWillUpdateViews.fire();
}
Expand All @@ -129,12 +117,6 @@ export class ViewModel implements IViewModel {
return this._onWillUpdateViews.event;
}

setSelectedBreakpoint(breakpoint: IFunctionBreakpoint | IExceptionBreakpoint | undefined): void {
this.selectedBreakpoint = breakpoint;
this.breakpointSelectedContextKey.set(!!breakpoint);
this._onDidSelectBreakpoint.fire(breakpoint);
}

isMultiSessionView(): boolean {
return !!this.multiSessionDebug.get();
}
Expand Down
Expand Up @@ -153,8 +153,8 @@ suite('Debug - Breakpoints', () => {
test('function breakpoints', () => {
model.addFunctionBreakpoint('foo', '1');
model.addFunctionBreakpoint('bar', '2');
model.renameFunctionBreakpoint('1', 'fooUpdated');
model.renameFunctionBreakpoint('2', 'barUpdated');
model.updateFunctionBreakpoint('1', { name: 'fooUpdated' });
model.updateFunctionBreakpoint('2', { name: 'barUpdated' });

const functionBps = model.getFunctionBreakpoints();
assert.equal(functionBps[0].name, 'fooUpdated');
Expand Down

0 comments on commit 7a9bb5a

Please sign in to comment.