Skip to content

Commit 026c2cb

Browse files
committed
Addresses PR feedback
1 parent 57b2a82 commit 026c2cb

5 files changed

Lines changed: 139 additions & 157 deletions

File tree

‎src/build/generate-contributions.ts‎

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1714,7 +1714,7 @@ const views = {
17141714
debug: [
17151715
{
17161716
id: CustomViews.EventListenerBreakpoints,
1717-
name: 'Event Listener Breakpoints',
1717+
name: 'Browser Options',
17181718
when: forBrowserDebugType('debugType'),
17191719
},
17201720
{
@@ -1727,11 +1727,6 @@ const views = {
17271727
name: 'Network',
17281728
when: ContextKey.NetworkAvailable,
17291729
},
1730-
{
1731-
id: CustomViews.DebugOptions,
1732-
name: 'JS Debug Options',
1733-
when: ContextKey.DebugOptionsAvailable,
1734-
},
17351730
],
17361731
};
17371732

‎src/common/contributionUtils.ts‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ export const enum CustomViews {
2727
XHRFetchBreakpoints = 'jsXHRBreakpoints',
2828
ExcludedCallers = 'jsExcludedCallers',
2929
Network = 'jsDebugNetworkTree',
30-
DebugOptions = 'jsDebugOptions',
3130
}
3231

3332
export const enum Commands {
@@ -314,7 +313,6 @@ export const enum ContextKey {
314313
IsProfiling = 'jsDebugIsProfiling',
315314
IsMapSteppingDisabled = 'jsDebugIsMapSteppingDisabled',
316315
NetworkAvailable = 'jsDebugNetworkAvailable',
317-
DebugOptionsAvailable = 'jsDebugOptionsAvailable',
318316
}
319317

320318
export interface IContextKeyTypes {
@@ -323,7 +321,6 @@ export interface IContextKeyTypes {
323321
[ContextKey.IsProfiling]: boolean;
324322
[ContextKey.IsMapSteppingDisabled]: boolean;
325323
[ContextKey.NetworkAvailable]: boolean;
326-
[ContextKey.DebugOptionsAvailable]: boolean;
327324
}
328325

329326
export const setContextKey = async <K extends keyof IContextKeyTypes>(

‎src/ui/customBreakpointsUI.ts‎

Lines changed: 138 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ import { l10n } from 'vscode';
77
import { customBreakpoints, ICustomBreakpoint, IXHRBreakpoint } from '../adapter/customBreakpoints';
88
import { Commands, CustomViews } from '../common/contributionUtils';
99
import { EventEmitter } from '../common/events';
10+
import Dap from '../dap/api';
1011
import { DebugSessionTracker } from './debugSessionTracker';
1112

1213
const xhrBreakpointsCategory = () => l10n.t('XHR/Fetch URLs');
14+
const focusEmulationStorageKey = 'jsDebug.focusEmulation.enabled';
1315

1416
class XHRBreakpoint extends vscode.TreeItem {
1517
public get checked() {
@@ -68,17 +70,47 @@ class Category extends vscode.TreeItem {
6870
}
6971
}
7072

71-
type TreeItem = Breakpoint | Category | XHRBreakpoint;
73+
class BreakpointsRoot extends vscode.TreeItem {
74+
public get checked() {
75+
return this.checkboxState === vscode.TreeItemCheckboxState.Checked;
76+
}
77+
78+
constructor() {
79+
super(l10n.t('Browser Breakpoints'), vscode.TreeItemCollapsibleState.Collapsed);
80+
this.checkboxState = vscode.TreeItemCheckboxState.Unchecked;
81+
this.id = 'browserBreakpoints';
82+
}
83+
}
84+
85+
class FocusEmulationOption extends vscode.TreeItem {
86+
constructor(enabled: boolean) {
87+
super(l10n.t('Emulate a focused page'), vscode.TreeItemCollapsibleState.None);
88+
this.checkboxState = enabled
89+
? vscode.TreeItemCheckboxState.Checked
90+
: vscode.TreeItemCheckboxState.Unchecked;
91+
this.tooltip = l10n.t(
92+
'When enabled, the debugged page will behave as if it has focus',
93+
);
94+
this.id = 'focusEmulation';
95+
}
96+
}
97+
98+
type BreakpointItem = BreakpointsRoot | Breakpoint | Category | XHRBreakpoint;
99+
type BrowserOptionItem = BreakpointItem | FocusEmulationOption;
72100

73-
class BreakpointsDataProvider implements vscode.TreeDataProvider<TreeItem> {
74-
private _onDidChangeTreeData = new EventEmitter<Breakpoint | undefined>();
101+
class BrowserOptionsDataProvider implements vscode.TreeDataProvider<BrowserOptionItem> {
102+
private _onDidChangeTreeData = new EventEmitter<BrowserOptionItem | undefined>();
75103
readonly onDidChangeTreeData = this._onDidChangeTreeData.event;
76104

77105
private _debugSessionTracker: DebugSessionTracker;
78106

107+
private readonly _breakpointsRoot = new BreakpointsRoot();
79108
private readonly categories = new Map<string, Category>();
80109
xhrBreakpoints: XHRBreakpoint[] = [];
81110

111+
private readonly _emulationSessions = new Set<string>();
112+
private _focusEmulationEnabled = false;
113+
82114
/** Gets all breakpoint categories */
83115
public get allCategories() {
84116
return this.categories.values();
@@ -89,7 +121,9 @@ class BreakpointsDataProvider implements vscode.TreeDataProvider<TreeItem> {
89121
return [...this.allCategories].flatMap(c => c.children);
90122
}
91123

92-
constructor(debugSessionTracker: DebugSessionTracker) {
124+
constructor(debugSessionTracker: DebugSessionTracker, focusEmulationEnabled: boolean) {
125+
this._focusEmulationEnabled = focusEmulationEnabled;
126+
93127
for (const breakpoint of [...customBreakpoints().values()]) {
94128
let category = this.categories.get(breakpoint.group);
95129
if (!category) {
@@ -113,25 +147,39 @@ class BreakpointsDataProvider implements vscode.TreeDataProvider<TreeItem> {
113147
}
114148

115149
const toEnable = this.allBreakpoints.filter(b => b.checked).map(b => b.id);
116-
if (toEnable.length === 0) {
117-
return;
150+
if (toEnable.length > 0) {
151+
session.customRequest('setCustomBreakpoints', {
152+
xhr: this.xhrBreakpoints.filter(b => b.checkboxState).map(b => b.id),
153+
ids: toEnable,
154+
});
118155
}
119156

120-
session.customRequest('setCustomBreakpoints', {
121-
xhr: this.xhrBreakpoints.filter(b => b.checkboxState).map(b => b.id),
122-
ids: toEnable,
123-
});
157+
this._checkEmulationSupport(session);
158+
});
159+
160+
debugSessionTracker.onSessionEnded(session => {
161+
if (this._emulationSessions.delete(session.id)) {
162+
this._onDidChangeTreeData.fire(undefined);
163+
}
124164
});
125165
}
126166

127167
/** @inheritdoc */
128-
getTreeItem(item: TreeItem): vscode.TreeItem {
168+
getTreeItem(item: BrowserOptionItem): vscode.TreeItem {
129169
return item;
130170
}
131171

132172
/** @inheritdoc */
133-
getChildren(item?: TreeItem): vscode.ProviderResult<TreeItem[]> {
173+
getChildren(item?: BrowserOptionItem): vscode.ProviderResult<BrowserOptionItem[]> {
134174
if (!item) {
175+
const items: BrowserOptionItem[] = [this._breakpointsRoot];
176+
if (this._emulationSessions.size > 0) {
177+
items.unshift(new FocusEmulationOption(this._focusEmulationEnabled));
178+
}
179+
return items;
180+
}
181+
182+
if (item instanceof BreakpointsRoot) {
135183
return [...this.categories.values()].sort((a, b) => a.label.localeCompare(b.label));
136184
}
137185

@@ -149,8 +197,10 @@ class BreakpointsDataProvider implements vscode.TreeDataProvider<TreeItem> {
149197
}
150198

151199
/** @inheritdoc */
152-
getParent(item: TreeItem): vscode.ProviderResult<TreeItem> {
153-
if (item instanceof Breakpoint) {
200+
getParent(item: BrowserOptionItem): vscode.ProviderResult<BrowserOptionItem> {
201+
if (item instanceof Category) {
202+
return this._breakpointsRoot;
203+
} else if (item instanceof Breakpoint) {
154204
return this.categories.get(item.group);
155205
} else if (item instanceof XHRBreakpoint) {
156206
return this.categories.get(xhrBreakpointsCategory());
@@ -159,21 +209,40 @@ class BreakpointsDataProvider implements vscode.TreeDataProvider<TreeItem> {
159209
return undefined;
160210
}
161211

212+
public setFocusEmulation(enabled: boolean): void {
213+
this._focusEmulationEnabled = enabled;
214+
this._onFocusEmulationChanged?.(enabled);
215+
this._applyFocusEmulationToAllSessions();
216+
this._onDidChangeTreeData.fire(undefined);
217+
}
218+
162219
/** Updates the enablement state of the breakpoints/categories */
163-
public setEnabled(breakpoints: [TreeItem, boolean][]) {
220+
public setBreakpointsEnabled(breakpoints: [BreakpointItem, boolean][]) {
164221
for (const [breakpoint, enabled] of breakpoints) {
165222
const state = enabled
166223
? vscode.TreeItemCheckboxState.Checked
167224
: vscode.TreeItemCheckboxState.Unchecked;
168225

169226
breakpoint.checkboxState = state;
170227

171-
if (breakpoint instanceof Category) {
228+
if (breakpoint instanceof BreakpointsRoot) {
229+
for (const category of this.categories.values()) {
230+
category.checkboxState = state;
231+
for (const child of category.children) {
232+
child.checkboxState = state;
233+
}
234+
}
235+
for (const xhr of this.xhrBreakpoints) {
236+
xhr.checkboxState = state;
237+
}
238+
this.syncXHRCategoryState();
239+
} else if (breakpoint instanceof Category) {
172240
for (const child of this.getChildren(breakpoint) as XHRBreakpoint[]) {
173241
if (child.checkboxState !== state) {
174242
child.checkboxState = state;
175243
}
176244
}
245+
this._syncBreakpointsRootState();
177246
} else if (breakpoint instanceof Breakpoint || breakpoint instanceof XHRBreakpoint) {
178247
const parent = this.getParent(breakpoint) as Category;
179248
if (!enabled && parent.checked) {
@@ -186,6 +255,7 @@ class BreakpointsDataProvider implements vscode.TreeDataProvider<TreeItem> {
186255
) {
187256
parent.checkboxState = state;
188257
}
258+
this._syncBreakpointsRootState();
189259
}
190260
}
191261

@@ -236,13 +306,50 @@ class BreakpointsDataProvider implements vscode.TreeDataProvider<TreeItem> {
236306
? vscode.TreeItemCheckboxState.Checked
237307
: vscode.TreeItemCheckboxState.Unchecked;
238308
}
309+
310+
private _syncBreakpointsRootState(): void {
311+
const allChecked = [...this.categories.values()].every(c => c.checked);
312+
this._breakpointsRoot.checkboxState = allChecked
313+
? vscode.TreeItemCheckboxState.Checked
314+
: vscode.TreeItemCheckboxState.Unchecked;
315+
}
316+
317+
_onFocusEmulationChanged?: (enabled: boolean) => void;
318+
319+
private async _checkEmulationSupport(session: vscode.DebugSession): Promise<void> {
320+
try {
321+
const result: Dap.CanEmulateResult = await session.customRequest('canEmulate', {});
322+
if (result.supported) {
323+
this._emulationSessions.add(session.id);
324+
this._onDidChangeTreeData.fire(undefined);
325+
326+
if (this._focusEmulationEnabled) {
327+
session.customRequest('setFocusEmulation', { enabled: true });
328+
}
329+
}
330+
} catch {
331+
// Session doesn't support emulation
332+
}
333+
}
334+
335+
private _applyFocusEmulationToAllSessions(): void {
336+
for (const sessionId of this._emulationSessions) {
337+
const session = this._debugSessionTracker.getById(sessionId);
338+
if (session) {
339+
session.customRequest('setFocusEmulation', { enabled: this._focusEmulationEnabled });
340+
}
341+
}
342+
}
239343
}
240344

241345
export function registerCustomBreakpointsUI(
242346
context: vscode.ExtensionContext,
243347
debugSessionTracker: DebugSessionTracker,
244348
) {
245-
const provider = new BreakpointsDataProvider(debugSessionTracker);
349+
const focusEmulationEnabled = context.workspaceState.get(focusEmulationStorageKey, false);
350+
const provider = new BrowserOptionsDataProvider(debugSessionTracker, focusEmulationEnabled);
351+
provider._onFocusEmulationChanged = enabled =>
352+
context.workspaceState.update(focusEmulationStorageKey, enabled);
246353

247354
const view = vscode.window.createTreeView(CustomViews.EventListenerBreakpoints, {
248355
treeDataProvider: provider,
@@ -252,9 +359,18 @@ export function registerCustomBreakpointsUI(
252359

253360
context.subscriptions.push(
254361
view.onDidChangeCheckboxState(async e => {
255-
provider.setEnabled(
256-
e.items.map(([i, state]) => [i, state === vscode.TreeItemCheckboxState.Checked]),
257-
);
362+
const breakpointChanges: [BreakpointItem, boolean][] = [];
363+
for (const [item, state] of e.items) {
364+
const enabled = state === vscode.TreeItemCheckboxState.Checked;
365+
if (item instanceof FocusEmulationOption) {
366+
provider.setFocusEmulation(enabled);
367+
} else {
368+
breakpointChanges.push([item as BreakpointItem, enabled]);
369+
}
370+
}
371+
if (breakpointChanges.length) {
372+
provider.setBreakpointsEnabled(breakpointChanges);
373+
}
258374
}),
259375
);
260376

@@ -287,13 +403,13 @@ export function registerCustomBreakpointsUI(
287403
}
288404

289405
const pickedSet = new Set(picked.map(i => i.id));
290-
provider.setEnabled(provider.allBreakpoints.map(i => [i, pickedSet.has(i.id)]));
406+
provider.setBreakpointsEnabled(provider.allBreakpoints.map(i => [i, pickedSet.has(i.id)]));
291407
}),
292408
);
293409

294410
context.subscriptions.push(
295411
vscode.commands.registerCommand(Commands.RemoveAllCustomBreakpoints, () => {
296-
provider.setEnabled(
412+
provider.setBreakpointsEnabled(
297413
[...provider.allBreakpoints, ...provider.xhrBreakpoints].map(bp => [bp, false]),
298414
);
299415
}),

0 commit comments

Comments
 (0)