chrome-devtools-frontend 1.0.1524741 → 1.0.1525561
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/policy/slow-close.md +22 -19
- package/front_end/{models/source_map_scopes → core/sdk}/ScopeTreeCache.ts +8 -7
- package/front_end/core/sdk/sdk.ts +2 -0
- package/front_end/entrypoints/formatter_worker/FormatterActions.ts +7 -0
- package/front_end/entrypoints/formatter_worker/ScopeParser.ts +15 -12
- package/front_end/models/formatter/FormatterWorkerPool.ts +1 -1
- package/front_end/models/source_map_scopes/NamesResolver.ts +1 -3
- package/front_end/models/source_map_scopes/source_map_scopes.ts +0 -2
- package/front_end/panels/changes/ChangesSidebar.ts +10 -3
- package/front_end/panels/changes/ChangesView.ts +69 -69
- package/front_end/panels/changes/CombinedDiffView.ts +1 -1
- package/front_end/panels/changes/changesView.css +4 -0
- package/front_end/panels/lighthouse/LighthouseController.ts +5 -0
- package/front_end/panels/linear_memory_inspector/LinearMemoryInspectorPane.ts +43 -46
- package/front_end/panels/linear_memory_inspector/components/LinearMemoryInspector.ts +254 -153
- package/front_end/panels/linear_memory_inspector/components/linearMemoryInspector.css +28 -21
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/components/docs/linear_memory_inspector/basic.ts +21 -9
- package/front_end/ui/components/highlighting/HighlightManager.ts +21 -1
- package/front_end/ui/components/tooltips/Tooltip.ts +22 -5
- package/front_end/ui/legacy/components/source_frame/StreamingContentHexView.ts +18 -20
- package/package.json +1 -1
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
<small>([go/chrome-devtools:slow-close-policy])</small>
|
|
5
5
|
|
|
6
6
|
In November 2024, we instituted a slow close policy for Chrome DevTools to
|
|
7
|
-
automatically maintain hygiene of our bug database. We ended up with a list
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
automatically maintain hygiene of our bug database. We ended up with a list of
|
|
8
|
+
over 1650 open bugs and over 750 open feature requests, some of them going back
|
|
9
|
+
over 10 years, which was not only challenging to maintain, but also made it
|
|
10
|
+
difficult to determine what's relevant and where we should invest our resources
|
|
11
|
+
best.
|
|
12
12
|
|
|
13
13
|
By automatically nudging and closing stale bugs and feature requests, we can
|
|
14
14
|
reduce this burden, and better communicate to our users what will actually be
|
|
@@ -20,28 +20,31 @@ actioned, and hear from them what remains relevant.
|
|
|
20
20
|
|
|
21
21
|
The criteria for slow close:
|
|
22
22
|
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
23
|
+
- Status: unassigned
|
|
24
|
+
- Type: Bug or Feature Request
|
|
25
|
+
- Created: over 3 years ago
|
|
26
|
+
- Last updated: over 90 days ago
|
|
27
|
+
- Popularity: (cc count + vote count) < 10
|
|
28
|
+
- No open descendants
|
|
29
29
|
|
|
30
30
|
Googlers can mark issues as exempt from slow close by adding them to the
|
|
31
31
|
[`DevTools-Blintz-Close-Exempt` hotlist](https://issues.chromium.org/hotlists/6459983).
|
|
32
|
+
All issues on the
|
|
33
|
+
[`ChromeTooling-Icebox`](https://issues.chromium.org/hotlists/7363836) are also
|
|
34
|
+
automatically exempt from slow close.
|
|
32
35
|
|
|
33
36
|
## Process
|
|
34
37
|
|
|
35
38
|
The automation runs on a daily basis, and performs the following steps:
|
|
36
39
|
|
|
37
|
-
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
-
|
|
40
|
+
- Issues that meet the criteria outlined above are added to the
|
|
41
|
+
[`DevTools-Blintz-Close-Candidate` hotlist](https://issues.chromium.org/hotlists/6459982)
|
|
42
|
+
for closure.
|
|
43
|
+
- If 14 days have passed and no updates have occurred, the issue will be
|
|
44
|
+
closed and moved to the
|
|
45
|
+
[`DevTools-Blintz-Close` hotlist](https://issues.chromium.org/hotlists/6460812)
|
|
46
|
+
for recording purposes.
|
|
47
|
+
- No more than 25 issues will be updated in a single run.
|
|
45
48
|
|
|
46
49
|
## Implementation
|
|
47
50
|
|
|
@@ -2,24 +2,25 @@
|
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import * as
|
|
7
|
-
|
|
5
|
+
import * as Formatter from '../../models/formatter/formatter.js';
|
|
6
|
+
import * as TextUtils from '../../models/text_utils/text_utils.js';
|
|
7
|
+
|
|
8
|
+
import type {Script} from './Script.js';
|
|
8
9
|
|
|
9
10
|
type ScopeTreeNode = Formatter.FormatterWorkerPool.ScopeTreeNode;
|
|
10
11
|
|
|
11
12
|
/** If a script failed to parse, we stash null in order to prevent unnecessary re-parsing */
|
|
12
|
-
const scopeTrees = new WeakMap<
|
|
13
|
+
const scopeTrees = new WeakMap<Script, Promise<ScopeTreeNode|null>>();
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Computes and caches the scope tree for `script`.
|
|
16
17
|
*
|
|
17
|
-
* We use {@link
|
|
18
|
-
* {@link
|
|
18
|
+
* We use {@link Script} as a key to uniquely identify scripts.
|
|
19
|
+
* {@link Script} boils down to "target" + "script ID". This
|
|
19
20
|
* duplicates work in case of identitical script running on multiple targets
|
|
20
21
|
* (e.g. workers).
|
|
21
22
|
*/
|
|
22
|
-
export function scopeTreeForScript(script:
|
|
23
|
+
export function scopeTreeForScript(script: Script): Promise<ScopeTreeNode|null> {
|
|
23
24
|
let promise = scopeTrees.get(script);
|
|
24
25
|
if (promise === undefined) {
|
|
25
26
|
promise = script.requestContentData().then(content => {
|
|
@@ -68,6 +68,7 @@ import * as RemoteObject from './RemoteObject.js';
|
|
|
68
68
|
import * as Resource from './Resource.js';
|
|
69
69
|
import * as ResourceTreeModel from './ResourceTreeModel.js';
|
|
70
70
|
import * as RuntimeModel from './RuntimeModel.js';
|
|
71
|
+
import * as ScopeTreeCache from './ScopeTreeCache.js';
|
|
71
72
|
import * as ScreenCaptureModel from './ScreenCaptureModel.js';
|
|
72
73
|
import * as Script from './Script.js';
|
|
73
74
|
import * as SDKModel from './SDKModel.js';
|
|
@@ -149,6 +150,7 @@ export {
|
|
|
149
150
|
Resource,
|
|
150
151
|
ResourceTreeModel,
|
|
151
152
|
RuntimeModel,
|
|
153
|
+
ScopeTreeCache,
|
|
152
154
|
ScreenCaptureModel,
|
|
153
155
|
Script,
|
|
154
156
|
SDKModel,
|
|
@@ -44,9 +44,16 @@ export const enum DefinitionKind {
|
|
|
44
44
|
FIXED = 3,
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
export const enum ScopeKind {
|
|
48
|
+
BLOCK = 1,
|
|
49
|
+
FUNCTION = 2,
|
|
50
|
+
GLOBAL = 3,
|
|
51
|
+
}
|
|
52
|
+
|
|
47
53
|
export interface ScopeTreeNode {
|
|
48
54
|
variables: Array<{name: string, kind: DefinitionKind, offsets: number[]}>;
|
|
49
55
|
start: number;
|
|
50
56
|
end: number;
|
|
57
|
+
kind: ScopeKind;
|
|
51
58
|
children: ScopeTreeNode[];
|
|
52
59
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import * as Acorn from '../../third_party/acorn/acorn.js';
|
|
6
6
|
|
|
7
7
|
import {ECMA_VERSION} from './AcornTokenizer.js';
|
|
8
|
-
import {DefinitionKind, type ScopeTreeNode} from './FormatterActions.js';
|
|
8
|
+
import {DefinitionKind, ScopeKind, type ScopeTreeNode} from './FormatterActions.js';
|
|
9
9
|
|
|
10
10
|
export function parseScopes(expression: string, sourceType: 'module'|'script' = 'script'): Scope|null {
|
|
11
11
|
// Parse the expression and find variables and scopes.
|
|
@@ -36,12 +36,14 @@ export class Scope {
|
|
|
36
36
|
readonly parent: Scope|null;
|
|
37
37
|
readonly start: number;
|
|
38
38
|
readonly end: number;
|
|
39
|
+
readonly kind: ScopeKind;
|
|
39
40
|
readonly children: Scope[] = [];
|
|
40
41
|
|
|
41
|
-
constructor(start: number, end: number, parent: Scope|null) {
|
|
42
|
+
constructor(start: number, end: number, parent: Scope|null, kind: ScopeKind) {
|
|
42
43
|
this.start = start;
|
|
43
44
|
this.end = end;
|
|
44
45
|
this.parent = parent;
|
|
46
|
+
this.kind = kind;
|
|
45
47
|
if (parent) {
|
|
46
48
|
parent.children.push(this);
|
|
47
49
|
}
|
|
@@ -61,6 +63,7 @@ export class Scope {
|
|
|
61
63
|
start: this.start,
|
|
62
64
|
end: this.end,
|
|
63
65
|
variables,
|
|
66
|
+
kind: this.kind,
|
|
64
67
|
children,
|
|
65
68
|
};
|
|
66
69
|
}
|
|
@@ -137,7 +140,7 @@ export class ScopeVariableAnalysis {
|
|
|
137
140
|
|
|
138
141
|
constructor(node: Acorn.ESTree.Node) {
|
|
139
142
|
this.#rootNode = node;
|
|
140
|
-
this.#rootScope = new Scope(node.start, node.end, null);
|
|
143
|
+
this.#rootScope = new Scope(node.start, node.end, null, ScopeKind.GLOBAL);
|
|
141
144
|
this.#currentScope = this.#rootScope;
|
|
142
145
|
}
|
|
143
146
|
|
|
@@ -169,7 +172,7 @@ export class ScopeVariableAnalysis {
|
|
|
169
172
|
node.elements.forEach(item => this.#processNode(item));
|
|
170
173
|
break;
|
|
171
174
|
case 'ArrowFunctionExpression': {
|
|
172
|
-
this.#pushScope(node.start, node.end);
|
|
175
|
+
this.#pushScope(node.start, node.end, ScopeKind.FUNCTION);
|
|
173
176
|
node.params.forEach(this.#processNodeAsDefinition.bind(this, DefinitionKind.VAR, false));
|
|
174
177
|
if (node.body.type === 'BlockStatement') {
|
|
175
178
|
// Include the body of the arrow function in the same scope as the arguments.
|
|
@@ -188,7 +191,7 @@ export class ScopeVariableAnalysis {
|
|
|
188
191
|
this.#processNode(node.right);
|
|
189
192
|
break;
|
|
190
193
|
case 'BlockStatement':
|
|
191
|
-
this.#pushScope(node.start, node.end);
|
|
194
|
+
this.#pushScope(node.start, node.end, ScopeKind.BLOCK);
|
|
192
195
|
node.body.forEach(this.#processNode.bind(this));
|
|
193
196
|
this.#popScope(false);
|
|
194
197
|
break;
|
|
@@ -202,7 +205,7 @@ export class ScopeVariableAnalysis {
|
|
|
202
205
|
break;
|
|
203
206
|
}
|
|
204
207
|
case 'CatchClause':
|
|
205
|
-
this.#pushScope(node.start, node.end);
|
|
208
|
+
this.#pushScope(node.start, node.end, ScopeKind.BLOCK);
|
|
206
209
|
this.#processNodeAsDefinition(DefinitionKind.LET, false, node.param);
|
|
207
210
|
this.#processNode(node.body);
|
|
208
211
|
this.#popScope(false);
|
|
@@ -234,14 +237,14 @@ export class ScopeVariableAnalysis {
|
|
|
234
237
|
break;
|
|
235
238
|
case 'ForInStatement':
|
|
236
239
|
case 'ForOfStatement':
|
|
237
|
-
this.#pushScope(node.start, node.end);
|
|
240
|
+
this.#pushScope(node.start, node.end, ScopeKind.BLOCK);
|
|
238
241
|
this.#processNode(node.left);
|
|
239
242
|
this.#processNode(node.right);
|
|
240
243
|
this.#processNode(node.body);
|
|
241
244
|
this.#popScope(false);
|
|
242
245
|
break;
|
|
243
246
|
case 'ForStatement':
|
|
244
|
-
this.#pushScope(node.start, node.end);
|
|
247
|
+
this.#pushScope(node.start, node.end, ScopeKind.BLOCK);
|
|
245
248
|
this.#processNode(node.init ?? null);
|
|
246
249
|
this.#processNode(node.test ?? null);
|
|
247
250
|
this.#processNode(node.update ?? null);
|
|
@@ -250,7 +253,7 @@ export class ScopeVariableAnalysis {
|
|
|
250
253
|
break;
|
|
251
254
|
case 'FunctionDeclaration':
|
|
252
255
|
this.#processNodeAsDefinition(DefinitionKind.VAR, false, node.id);
|
|
253
|
-
this.#pushScope(node.id?.end ?? node.start, node.end);
|
|
256
|
+
this.#pushScope(node.id?.end ?? node.start, node.end, ScopeKind.FUNCTION);
|
|
254
257
|
this.#addVariable('this', node.start, DefinitionKind.FIXED);
|
|
255
258
|
this.#addVariable('arguments', node.start, DefinitionKind.FIXED);
|
|
256
259
|
node.params.forEach(this.#processNodeAsDefinition.bind(this, DefinitionKind.LET, false));
|
|
@@ -259,7 +262,7 @@ export class ScopeVariableAnalysis {
|
|
|
259
262
|
this.#popScope(true);
|
|
260
263
|
break;
|
|
261
264
|
case 'FunctionExpression':
|
|
262
|
-
this.#pushScope(node.id?.end ?? node.start, node.end);
|
|
265
|
+
this.#pushScope(node.id?.end ?? node.start, node.end, ScopeKind.FUNCTION);
|
|
263
266
|
this.#addVariable('this', node.start, DefinitionKind.FIXED);
|
|
264
267
|
this.#addVariable('arguments', node.start, DefinitionKind.FIXED);
|
|
265
268
|
node.params.forEach(this.#processNodeAsDefinition.bind(this, DefinitionKind.LET, false));
|
|
@@ -421,8 +424,8 @@ export class ScopeVariableAnalysis {
|
|
|
421
424
|
return this.#allNames;
|
|
422
425
|
}
|
|
423
426
|
|
|
424
|
-
#pushScope(start: number, end: number): void {
|
|
425
|
-
this.#currentScope = new Scope(start, end, this.#currentScope);
|
|
427
|
+
#pushScope(start: number, end: number, kind: ScopeKind): void {
|
|
428
|
+
this.#currentScope = new Scope(start, end, this.#currentScope, kind);
|
|
426
429
|
}
|
|
427
430
|
|
|
428
431
|
#popScope(isFunctionContext: boolean): void {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import * as Common from '../../core/common/common.js';
|
|
6
6
|
import * as FormatterActions from '../../entrypoints/formatter_worker/FormatterActions.js'; // eslint-disable-line rulesdir/es-modules-import
|
|
7
7
|
|
|
8
|
-
export {DefinitionKind, type ScopeTreeNode} from '../../entrypoints/formatter_worker/FormatterActions.js';
|
|
8
|
+
export {DefinitionKind, ScopeKind, type ScopeTreeNode} from '../../entrypoints/formatter_worker/FormatterActions.js';
|
|
9
9
|
|
|
10
10
|
let formatterWorkerPoolInstance: FormatterWorkerPool;
|
|
11
11
|
|
|
@@ -9,8 +9,6 @@ import * as Bindings from '../bindings/bindings.js';
|
|
|
9
9
|
import * as Formatter from '../formatter/formatter.js';
|
|
10
10
|
import * as TextUtils from '../text_utils/text_utils.js';
|
|
11
11
|
|
|
12
|
-
import {scopeTreeForScript} from './ScopeTreeCache.js';
|
|
13
|
-
|
|
14
12
|
interface CachedScopeMap {
|
|
15
13
|
sourceMap: SDK.SourceMap.SourceMap|undefined;
|
|
16
14
|
mappingPromise: Promise<{variableMapping: Map<string, string>, thisMapping: string|null}>;
|
|
@@ -55,7 +53,7 @@ scopeTree:
|
|
|
55
53
|
return null;
|
|
56
54
|
}
|
|
57
55
|
|
|
58
|
-
const scopeTree = await scopeTreeForScript(script);
|
|
56
|
+
const scopeTree = await SDK.ScopeTreeCache.scopeTreeForScript(script);
|
|
59
57
|
if (!scopeTree) {
|
|
60
58
|
return null;
|
|
61
59
|
}
|
|
@@ -67,14 +67,21 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
|
67
67
|
|
|
68
68
|
export class ChangesSidebar extends Common.ObjectWrapper.eventMixin<EventTypes, typeof UI.Widget.Widget>(
|
|
69
69
|
UI.Widget.Widget) {
|
|
70
|
-
|
|
70
|
+
#workspaceDiff: WorkspaceDiff.WorkspaceDiff.WorkspaceDiffImpl|null = null;
|
|
71
71
|
readonly #view: View;
|
|
72
72
|
readonly #sourceCodes = new Set<Workspace.UISourceCode.UISourceCode>();
|
|
73
73
|
#selectedUISourceCode: Workspace.UISourceCode.UISourceCode|null = null;
|
|
74
|
-
constructor(
|
|
75
|
-
super({jslog: `${VisualLogging.pane('sidebar').track({resize: true})}`});
|
|
74
|
+
constructor(target?: HTMLElement, view = DEFAULT_VIEW) {
|
|
75
|
+
super(target, {jslog: `${VisualLogging.pane('sidebar').track({resize: true})}`});
|
|
76
76
|
this.#view = view;
|
|
77
|
+
}
|
|
77
78
|
|
|
79
|
+
set workspaceDiff(workspaceDiff: WorkspaceDiff.WorkspaceDiff.WorkspaceDiffImpl) {
|
|
80
|
+
if (this.#workspaceDiff) {
|
|
81
|
+
this.#workspaceDiff.modifiedUISourceCodes().forEach(this.#removeUISourceCode.bind(this));
|
|
82
|
+
this.#workspaceDiff.removeEventListener(
|
|
83
|
+
WorkspaceDiff.WorkspaceDiff.Events.MODIFIED_STATUS_CHANGED, this.uiSourceCodeModifiedStatusChanged, this);
|
|
84
|
+
}
|
|
78
85
|
this.#workspaceDiff = workspaceDiff;
|
|
79
86
|
this.#workspaceDiff.modifiedUISourceCodes().forEach(this.#addUISourceCode.bind(this));
|
|
80
87
|
this.#workspaceDiff.addEventListener(
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// Copyright 2017 The Chromium Authors
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
|
-
/* eslint-disable rulesdir/no-imperative-dom-api */
|
|
5
4
|
|
|
6
5
|
import '../../ui/legacy/legacy.js';
|
|
7
6
|
|
|
@@ -10,6 +9,7 @@ import type * as Platform from '../../core/platform/platform.js';
|
|
|
10
9
|
import type * as Workspace from '../../models/workspace/workspace.js';
|
|
11
10
|
import * as WorkspaceDiff from '../../models/workspace_diff/workspace_diff.js';
|
|
12
11
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
12
|
+
import * as Lit from '../../ui/lit/lit.js';
|
|
13
13
|
import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
|
|
14
14
|
|
|
15
15
|
import {ChangesSidebar, Events} from './ChangesSidebar.js';
|
|
@@ -30,93 +30,93 @@ const UIStrings = {
|
|
|
30
30
|
} as const;
|
|
31
31
|
const str_ = i18n.i18n.registerUIStrings('panels/changes/ChangesView.ts', UIStrings);
|
|
32
32
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
33
|
+
const {render, html} = Lit;
|
|
34
|
+
interface ViewInput {
|
|
35
|
+
selectedSourceCode: Workspace.UISourceCode.UISourceCode|null;
|
|
36
|
+
onSelect(sourceCode: Workspace.UISourceCode.UISourceCode|null): void;
|
|
37
|
+
workspaceDiff: WorkspaceDiff.WorkspaceDiff.WorkspaceDiffImpl;
|
|
38
|
+
}
|
|
39
|
+
type View = (input: ViewInput, output: object, target: HTMLElement) => void;
|
|
40
|
+
export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
41
|
+
const onSidebar = (sidebar: ChangesSidebar): void => {
|
|
42
|
+
sidebar.addEventListener(
|
|
43
|
+
Events.SELECTED_UI_SOURCE_CODE_CHANGED, () => input.onSelect(sidebar.selectedUISourceCode()));
|
|
44
|
+
};
|
|
45
|
+
render(
|
|
46
|
+
// clang-format off
|
|
47
|
+
html`
|
|
48
|
+
<style>${changesViewStyles}</style>
|
|
49
|
+
<devtools-split-view direction=column>
|
|
50
|
+
<div class=vbox slot="main">
|
|
51
|
+
<devtools-widget
|
|
52
|
+
?hidden=${input.workspaceDiff.modifiedUISourceCodes().length > 0}
|
|
53
|
+
.widgetConfig=${UI.Widget.widgetConfig(UI.EmptyWidget.EmptyWidget, {
|
|
54
|
+
header: i18nString(UIStrings.noChanges),
|
|
55
|
+
text: i18nString(UIStrings.changesViewDescription),
|
|
56
|
+
link: CHANGES_VIEW_URL,
|
|
57
|
+
})}>
|
|
58
|
+
</devtools-widget>
|
|
59
|
+
<div class=diff-container role=tabpanel ?hidden=${input.workspaceDiff.modifiedUISourceCodes().length === 0}>
|
|
60
|
+
<devtools-widget .widgetConfig=${UI.Widget.widgetConfig(CombinedDiffView.CombinedDiffView, {
|
|
61
|
+
selectedFileUrl: input.selectedSourceCode?.url(),
|
|
62
|
+
workspaceDiff: input.workspaceDiff
|
|
63
|
+
})}></devtools-widget>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
<devtools-widget
|
|
67
|
+
slot="sidebar"
|
|
68
|
+
.widgetConfig=${UI.Widget.widgetConfig(ChangesSidebar, {
|
|
69
|
+
workspaceDiff: input.workspaceDiff
|
|
70
|
+
})}
|
|
71
|
+
${UI.Widget.widgetRef(ChangesSidebar, onSidebar)}>
|
|
72
|
+
</devtools-widget>
|
|
73
|
+
</devtools-split-view>`,
|
|
74
|
+
// clang-format on
|
|
75
|
+
target);
|
|
76
|
+
};
|
|
33
77
|
|
|
34
78
|
export class ChangesView extends UI.Widget.VBox {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
readonly
|
|
38
|
-
private selectedUISourceCode: Workspace.UISourceCode.UISourceCode|null;
|
|
39
|
-
private readonly diffContainer: HTMLElement;
|
|
40
|
-
private readonly combinedDiffView: CombinedDiffView.CombinedDiffView;
|
|
79
|
+
readonly #workspaceDiff: WorkspaceDiff.WorkspaceDiff.WorkspaceDiffImpl;
|
|
80
|
+
#selectedUISourceCode: Workspace.UISourceCode.UISourceCode|null = null;
|
|
81
|
+
readonly #view: View;
|
|
41
82
|
|
|
42
|
-
constructor() {
|
|
43
|
-
super({
|
|
83
|
+
constructor(target?: HTMLElement, view = DEFAULT_VIEW) {
|
|
84
|
+
super(target, {
|
|
44
85
|
jslog: `${VisualLogging.panel('changes').track({resize: true})}`,
|
|
45
86
|
useShadowDom: true,
|
|
46
87
|
});
|
|
47
|
-
this.registerRequiredCSS(changesViewStyles);
|
|
48
|
-
|
|
49
|
-
const splitWidget = new UI.SplitWidget.SplitWidget(true /* vertical */, false /* sidebar on left */);
|
|
50
|
-
const mainWidget = new UI.Widget.VBox();
|
|
51
|
-
splitWidget.setMainWidget(mainWidget);
|
|
52
|
-
splitWidget.show(this.contentElement);
|
|
53
|
-
|
|
54
|
-
this.emptyWidget = new UI.EmptyWidget.EmptyWidget('', '');
|
|
55
|
-
this.emptyWidget.show(mainWidget.element);
|
|
56
|
-
|
|
57
|
-
this.workspaceDiff = WorkspaceDiff.WorkspaceDiff.workspaceDiff();
|
|
58
|
-
this.changesSidebar = new ChangesSidebar(this.workspaceDiff);
|
|
59
|
-
this.changesSidebar.addEventListener(
|
|
60
|
-
Events.SELECTED_UI_SOURCE_CODE_CHANGED, this.selectedUISourceCodeChanged, this);
|
|
61
|
-
splitWidget.setSidebarWidget(this.changesSidebar);
|
|
62
88
|
|
|
63
|
-
this
|
|
89
|
+
this.#workspaceDiff = WorkspaceDiff.WorkspaceDiff.workspaceDiff();
|
|
90
|
+
this.#view = view;
|
|
64
91
|
|
|
65
|
-
this.
|
|
66
|
-
UI.ARIAUtils.markAsTabpanel(this.diffContainer);
|
|
67
|
-
this.combinedDiffView = new CombinedDiffView.CombinedDiffView();
|
|
68
|
-
this.combinedDiffView.workspaceDiff = this.workspaceDiff;
|
|
69
|
-
this.combinedDiffView.show(this.diffContainer);
|
|
70
|
-
|
|
71
|
-
this.hideDiff();
|
|
72
|
-
this.selectedUISourceCodeChanged();
|
|
92
|
+
this.requestUpdate();
|
|
73
93
|
}
|
|
74
94
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (!selectedUISourceCode || this.selectedUISourceCode === selectedUISourceCode) {
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
this.selectedUISourceCode = selectedUISourceCode;
|
|
91
|
-
this.combinedDiffView.selectedFileUrl = selectedUISourceCode.url();
|
|
95
|
+
override performUpdate(): void {
|
|
96
|
+
this.#view(
|
|
97
|
+
{
|
|
98
|
+
workspaceDiff: this.#workspaceDiff,
|
|
99
|
+
selectedSourceCode: this.#selectedUISourceCode,
|
|
100
|
+
onSelect: sourceCode => {
|
|
101
|
+
this.#selectedUISourceCode = sourceCode;
|
|
102
|
+
this.requestUpdate();
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
{}, this.contentElement);
|
|
92
106
|
}
|
|
93
107
|
|
|
94
108
|
override wasShown(): void {
|
|
95
109
|
UI.Context.Context.instance().setFlavor(ChangesView, this);
|
|
96
110
|
super.wasShown();
|
|
97
|
-
this.
|
|
98
|
-
this
|
|
99
|
-
WorkspaceDiff.WorkspaceDiff.Events.MODIFIED_STATUS_CHANGED, this.
|
|
111
|
+
this.requestUpdate();
|
|
112
|
+
this.#workspaceDiff.addEventListener(
|
|
113
|
+
WorkspaceDiff.WorkspaceDiff.Events.MODIFIED_STATUS_CHANGED, this.requestUpdate, this);
|
|
100
114
|
}
|
|
101
115
|
|
|
102
116
|
override willHide(): void {
|
|
103
117
|
super.willHide();
|
|
104
118
|
UI.Context.Context.instance().setFlavor(ChangesView, null);
|
|
105
|
-
this
|
|
106
|
-
WorkspaceDiff.WorkspaceDiff.Events.MODIFIED_STATUS_CHANGED, this.
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
private hideDiff(): void {
|
|
110
|
-
this.diffContainer.style.display = 'none';
|
|
111
|
-
this.emptyWidget.header = i18nString(UIStrings.noChanges);
|
|
112
|
-
this.emptyWidget.text = i18nString(UIStrings.changesViewDescription);
|
|
113
|
-
|
|
114
|
-
this.emptyWidget.link = CHANGES_VIEW_URL;
|
|
115
|
-
this.emptyWidget.showWidget();
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
private showDiff(): void {
|
|
119
|
-
this.emptyWidget.hideWidget();
|
|
120
|
-
this.diffContainer.style.display = 'block';
|
|
119
|
+
this.#workspaceDiff.removeEventListener(
|
|
120
|
+
WorkspaceDiff.WorkspaceDiff.Events.MODIFIED_STATUS_CHANGED, this.requestUpdate, this);
|
|
121
121
|
}
|
|
122
122
|
}
|
|
@@ -149,7 +149,7 @@ export class CombinedDiffView extends UI.Widget.Widget {
|
|
|
149
149
|
void this.#initializeModifiedUISourceCodes();
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
set selectedFileUrl(fileUrl: string) {
|
|
152
|
+
set selectedFileUrl(fileUrl: string|undefined) {
|
|
153
153
|
this.#selectedFileUrl = fileUrl;
|
|
154
154
|
this.requestUpdate();
|
|
155
155
|
void this.updateComplete.then(() => {
|
|
@@ -401,8 +401,13 @@ export class LighthouseController extends Common.ObjectWrapper.ObjectWrapper<Eve
|
|
|
401
401
|
}
|
|
402
402
|
|
|
403
403
|
getCategoryIDs(): string[] {
|
|
404
|
+
const {mode} = this.getFlags();
|
|
404
405
|
const categoryIDs = [];
|
|
405
406
|
for (const preset of Presets) {
|
|
407
|
+
if (mode && !preset.supportedModes.includes(mode)) {
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
|
|
406
411
|
if (preset.setting.get()) {
|
|
407
412
|
categoryIDs.push(preset.configID);
|
|
408
413
|
}
|
|
@@ -122,6 +122,8 @@ export interface EventTypes {
|
|
|
122
122
|
|
|
123
123
|
export class LinearMemoryInspectorView extends UI.Widget.VBox {
|
|
124
124
|
#memoryWrapper: LazyUint8Array;
|
|
125
|
+
#memory?: Uint8Array<ArrayBuffer>;
|
|
126
|
+
#offset = 0;
|
|
125
127
|
#address: number;
|
|
126
128
|
#tabId: string;
|
|
127
129
|
#inspector: LinearMemoryInspectorComponents.LinearMemoryInspector.LinearMemoryInspector;
|
|
@@ -140,32 +142,52 @@ export class LinearMemoryInspectorView extends UI.Widget.VBox {
|
|
|
140
142
|
this.#address = address;
|
|
141
143
|
this.#tabId = tabId;
|
|
142
144
|
this.#hideValueInspector = Boolean(hideValueInspector);
|
|
145
|
+
this.firstTimeOpen = true;
|
|
146
|
+
|
|
143
147
|
this.#inspector = new LinearMemoryInspectorComponents.LinearMemoryInspector.LinearMemoryInspector();
|
|
144
|
-
this.#inspector.addEventListener(
|
|
148
|
+
this.#inspector.contentElement.addEventListener(
|
|
145
149
|
LinearMemoryInspectorComponents.LinearMemoryInspector.MemoryRequestEvent.eventName,
|
|
146
|
-
(event: LinearMemoryInspectorComponents.LinearMemoryInspector.MemoryRequestEvent) =>
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
this.#inspector.addEventListener(
|
|
150
|
+
(event: LinearMemoryInspectorComponents.LinearMemoryInspector.MemoryRequestEvent) =>
|
|
151
|
+
this.#memoryRequested(event));
|
|
152
|
+
this.#inspector.contentElement.addEventListener(
|
|
150
153
|
LinearMemoryInspectorComponents.LinearMemoryInspector.AddressChangedEvent.eventName,
|
|
151
|
-
(event: LinearMemoryInspectorComponents.LinearMemoryInspector.AddressChangedEvent) =>
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
this.#inspector.addEventListener(
|
|
154
|
+
(event: LinearMemoryInspectorComponents.LinearMemoryInspector.AddressChangedEvent) =>
|
|
155
|
+
this.updateAddress(event.data));
|
|
156
|
+
this.#inspector.contentElement.addEventListener(
|
|
155
157
|
LinearMemoryInspectorComponents.LinearMemoryInspector.SettingsChangedEvent.eventName,
|
|
156
158
|
(event: LinearMemoryInspectorComponents.LinearMemoryInspector.SettingsChangedEvent) => {
|
|
157
159
|
// Stop event from bubbling up, since no element further up needs the event.
|
|
158
160
|
event.stopPropagation();
|
|
159
161
|
this.saveSettings(event.data);
|
|
160
162
|
});
|
|
161
|
-
this.#inspector.addEventListener(
|
|
163
|
+
this.#inspector.contentElement.addEventListener(
|
|
162
164
|
LinearMemoryInspectorComponents.LinearMemoryHighlightChipList.DeleteMemoryHighlightEvent.eventName,
|
|
163
165
|
(event: LinearMemoryInspectorComponents.LinearMemoryHighlightChipList.DeleteMemoryHighlightEvent) => {
|
|
164
166
|
LinearMemoryInspectorController.instance().removeHighlight(this.#tabId, event.data);
|
|
165
167
|
this.refreshData();
|
|
166
168
|
});
|
|
167
|
-
this.
|
|
168
|
-
|
|
169
|
+
this.#inspector.show(this.contentElement);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
render(): void {
|
|
173
|
+
if (this.firstTimeOpen) {
|
|
174
|
+
const settings = LinearMemoryInspectorController.instance().loadSettings();
|
|
175
|
+
this.#inspector.valueTypes = settings.valueTypes;
|
|
176
|
+
this.#inspector.valueTypeModes = settings.modes;
|
|
177
|
+
this.#inspector.endianness = settings.endianness;
|
|
178
|
+
this.firstTimeOpen = false;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (!this.#memory) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
this.#inspector.memory = this.#memory;
|
|
186
|
+
this.#inspector.memoryOffset = this.#offset;
|
|
187
|
+
this.#inspector.address = this.#address;
|
|
188
|
+
this.#inspector.outerMemoryLength = this.#memoryWrapper.length();
|
|
189
|
+
this.#inspector.highlightInfo = this.#getHighlightInfo();
|
|
190
|
+
this.#inspector.hideValueInspector = this.#hideValueInspector;
|
|
169
191
|
}
|
|
170
192
|
|
|
171
193
|
override wasShown(): void {
|
|
@@ -184,32 +206,12 @@ export class LinearMemoryInspectorView extends UI.Widget.VBox {
|
|
|
184
206
|
}
|
|
185
207
|
|
|
186
208
|
refreshData(): void {
|
|
187
|
-
void LinearMemoryInspectorController.getMemoryForAddress(this.#memoryWrapper, this.#address)
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
let endianness;
|
|
194
|
-
if (this.firstTimeOpen) {
|
|
195
|
-
const settings = LinearMemoryInspectorController.instance().loadSettings();
|
|
196
|
-
valueTypes = settings.valueTypes;
|
|
197
|
-
valueTypeModes = settings.modes;
|
|
198
|
-
endianness = settings.endianness;
|
|
199
|
-
this.firstTimeOpen = false;
|
|
200
|
-
}
|
|
201
|
-
this.#inspector.data = {
|
|
202
|
-
memory,
|
|
203
|
-
address: this.#address,
|
|
204
|
-
memoryOffset: offset,
|
|
205
|
-
outerMemoryLength: this.#memoryWrapper.length(),
|
|
206
|
-
valueTypes,
|
|
207
|
-
valueTypeModes,
|
|
208
|
-
endianness,
|
|
209
|
-
highlightInfo: this.#getHighlightInfo(),
|
|
210
|
-
hideValueInspector: this.#hideValueInspector,
|
|
211
|
-
};
|
|
212
|
-
});
|
|
209
|
+
void LinearMemoryInspectorController.getMemoryForAddress(this.#memoryWrapper, this.#address)
|
|
210
|
+
.then(({memory, offset}) => {
|
|
211
|
+
this.#memory = memory;
|
|
212
|
+
this.#offset = offset;
|
|
213
|
+
this.render();
|
|
214
|
+
});
|
|
213
215
|
}
|
|
214
216
|
|
|
215
217
|
#memoryRequested(event: LinearMemoryInspectorComponents.LinearMemoryInspector.MemoryRequestEvent): void {
|
|
@@ -219,14 +221,9 @@ export class LinearMemoryInspectorView extends UI.Widget.VBox {
|
|
|
219
221
|
}
|
|
220
222
|
|
|
221
223
|
void LinearMemoryInspectorController.getMemoryRange(this.#memoryWrapper, start, end).then(memory => {
|
|
222
|
-
this.#
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
memoryOffset: start,
|
|
226
|
-
outerMemoryLength: this.#memoryWrapper.length(),
|
|
227
|
-
highlightInfo: this.#getHighlightInfo(),
|
|
228
|
-
hideValueInspector: this.#hideValueInspector,
|
|
229
|
-
};
|
|
224
|
+
this.#memory = memory;
|
|
225
|
+
this.#offset = start;
|
|
226
|
+
this.render();
|
|
230
227
|
});
|
|
231
228
|
}
|
|
232
229
|
|