chrome-devtools-frontend 1.0.1518653 → 1.0.1520139
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/config/owner/COMMON_OWNERS +1 -2
- package/config/typescript/tsconfig.eslint.json +12 -1
- package/docs/ui_engineering.md +1011 -0
- package/eslint.config.mjs +1 -0
- package/front_end/core/host/GdpClient.ts +12 -3
- package/front_end/core/sdk/EnhancedTracesParser.ts +5 -5
- package/front_end/core/sdk/NetworkManager.ts +1 -0
- package/front_end/core/sdk/NetworkRequest.ts +10 -0
- package/front_end/core/sdk/RehydratingConnection.snapshot.txt +211 -0
- package/front_end/core/sdk/TargetManager.ts +4 -0
- package/front_end/entrypoints/main/MainImpl.ts +6 -1
- package/front_end/entrypoints/main/main-meta.ts +3 -3
- package/front_end/generated/SupportedCSSProperties.js +19 -4
- package/front_end/models/ai_assistance/agents/AiAgent.ts +57 -10
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +64 -87
- package/front_end/models/ai_assistance/agents/PerformanceAnnotationsAgent.ts +4 -4
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +0 -31
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +127 -29
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +106 -55
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +317 -640
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +23 -19
- package/front_end/models/ai_assistance/performance/AICallTree.snapshot.txt +75 -0
- package/front_end/models/ai_assistance/performance/AICallTree.ts +14 -6
- package/front_end/models/ai_assistance/performance/AIContext.ts +63 -8
- package/front_end/models/ai_code_completion/AiCodeCompletion.ts +5 -0
- package/front_end/models/badges/AiExplorerBadge.ts +19 -3
- package/front_end/models/badges/Badge.ts +8 -1
- package/front_end/models/badges/CodeWhispererBadge.ts +1 -0
- package/front_end/models/badges/DOMDetectiveBadge.ts +1 -0
- package/front_end/models/badges/SpeedsterBadge.ts +1 -0
- package/front_end/models/badges/StarterBadge.ts +6 -0
- package/front_end/models/badges/badges.ts +1 -0
- package/front_end/models/javascript_metadata/NativeFunctions.js +4 -0
- package/front_end/models/trace/EventsSerializer.ts +4 -3
- package/front_end/models/trace/handlers/UserInteractionsHandler.ts +101 -73
- package/front_end/models/trace/helpers/Timing.ts +1 -1
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +18 -8
- package/front_end/panels/ai_assistance/PatchWidget.ts +17 -55
- package/front_end/panels/ai_assistance/components/ChatView.ts +44 -68
- package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +63 -15
- package/front_end/panels/ai_assistance/components/chatView.css +12 -0
- package/front_end/panels/animation/AnimationTimeline.ts +1 -1
- package/front_end/panels/animation/animationTimeline.css +4 -0
- package/front_end/panels/application/components/BounceTrackingMitigationsView.ts +2 -2
- package/front_end/panels/application/preloading/components/PreloadingString.ts +2 -5
- package/front_end/panels/common/AiCodeCompletionTeaser.ts +5 -0
- package/front_end/panels/common/BadgeNotification.ts +3 -3
- package/front_end/panels/common/GdpSignUpDialog.ts +3 -4
- package/front_end/panels/common/aiCodeCompletionTeaser.css +6 -1
- package/front_end/panels/console/ConsolePrompt.ts +6 -0
- package/front_end/panels/console/ConsoleView.ts +4 -2
- package/front_end/panels/coverage/CoverageListView.ts +133 -158
- package/front_end/panels/coverage/CoverageView.ts +39 -16
- package/front_end/panels/css_overview/CSSOverviewCompletedView.ts +5 -5
- package/front_end/panels/mobile_throttling/NetworkThrottlingSelector.ts +2 -0
- package/front_end/panels/network/NetworkDataGridNode.ts +22 -0
- package/front_end/panels/network/NetworkLogViewColumns.ts +9 -0
- package/front_end/panels/recorder/components/CreateRecordingView.ts +2 -0
- package/front_end/panels/recorder/components/RecordingView.ts +2 -2
- package/front_end/panels/search/SearchResultsPane.ts +186 -134
- package/front_end/panels/search/SearchView.ts +42 -36
- package/front_end/panels/search/searchResultsPane.css +9 -0
- package/front_end/panels/search/searchView.css +0 -2
- package/front_end/panels/security/CookieControlsView.ts +2 -1
- package/front_end/panels/settings/AISettingsTab.ts +6 -3
- package/front_end/panels/settings/components/SyncSection.ts +26 -12
- package/front_end/panels/settings/emulation/components/UserAgentClientHintsForm.ts +1 -1
- package/front_end/panels/sources/AiCodeCompletionPlugin.ts +4 -4
- package/front_end/panels/sources/DebuggerPlugin.ts +4 -0
- package/front_end/panels/sources/SourcesPanel.ts +1 -1
- package/front_end/panels/sources/sourcesView.css +6 -1
- package/front_end/panels/timeline/ThirdPartyTreeView.ts +1 -1
- package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +0 -8
- package/front_end/panels/timeline/TimelineFlameChartView.ts +5 -5
- package/front_end/panels/timeline/TimelinePanel.ts +2 -0
- package/front_end/panels/timeline/TimelineTreeView.ts +1 -1
- package/front_end/panels/timeline/components/LayoutShiftDetails.ts +1 -1
- package/front_end/panels/timeline/components/NetworkRequestDetails.ts +1 -1
- package/front_end/panels/timeline/components/RelatedInsightChips.ts +1 -1
- package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +1 -1
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/puppeteer/README.chromium +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Realm.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/injected.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/injected.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserLauncher.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserLauncher.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/ChromeLauncher.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/ChromeLauncher.js +1 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/ChromeLauncher.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/PipeTransport.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/PipeTransport.js +15 -16
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/PipeTransport.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +3 -3
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +3 -3
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Function.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Function.js +16 -25
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Function.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +19 -28
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/injected.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/injected.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserLauncher.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserLauncher.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/ChromeLauncher.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/ChromeLauncher.js +1 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/ChromeLauncher.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/PipeTransport.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/PipeTransport.js +15 -16
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/PipeTransport.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +3 -3
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +3 -3
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/Function.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/Function.js +16 -25
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/Function.js.map +1 -1
- package/front_end/third_party/puppeteer/package/package.json +12 -4
- package/front_end/third_party/puppeteer/package/src/generated/injected.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/generated/version.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/node/BrowserLauncher.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/node/ChromeLauncher.ts +1 -0
- package/front_end/third_party/puppeteer/package/src/node/PipeTransport.ts +15 -17
- package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
- package/front_end/third_party/puppeteer/package/src/util/Function.ts +22 -30
- package/front_end/tsconfig.json +12 -1
- package/front_end/ui/components/dialogs/Dialog.ts +1 -1
- package/front_end/ui/components/markdown_view/MarkdownImage.ts +4 -5
- package/front_end/ui/components/switch/SwitchImpl.ts +12 -1
- package/front_end/ui/components/text_editor/config.ts +16 -2
- package/front_end/ui/legacy/InspectorView.ts +86 -13
- package/front_end/ui/legacy/TabbedPane.ts +2 -1
- package/front_end/ui/legacy/Treeoutline.ts +3 -1
- package/front_end/ui/legacy/components/source_frame/XMLView.ts +12 -11
- package/front_end/ui/lit/i18n-template.ts +5 -2
- package/front_end/ui/visual_logging/KnownContextValues.ts +15 -5
- package/front_end/ui/visual_logging/LoggingEvents.ts +1 -1
- package/package.json +1 -1
@@ -17,7 +17,7 @@ export class PipeTransport implements ConnectionTransport {
|
|
17
17
|
#subscriptions = new DisposableStack();
|
18
18
|
|
19
19
|
#isClosed = false;
|
20
|
-
#pendingMessage =
|
20
|
+
#pendingMessage: Buffer[] = [];
|
21
21
|
|
22
22
|
onclose?: () => void;
|
23
23
|
onmessage?: (value: string) => void;
|
@@ -34,7 +34,7 @@ export class PipeTransport implements ConnectionTransport {
|
|
34
34
|
pipeRead as unknown as EventEmitter<Record<string, any>>,
|
35
35
|
),
|
36
36
|
);
|
37
|
-
pipeReadEmitter.on('data',
|
37
|
+
pipeReadEmitter.on('data', buffer => {
|
38
38
|
return this.#dispatch(buffer);
|
39
39
|
});
|
40
40
|
pipeReadEmitter.on('close', () => {
|
@@ -60,34 +60,32 @@ export class PipeTransport implements ConnectionTransport {
|
|
60
60
|
this.#pipeWrite.write('\0');
|
61
61
|
}
|
62
62
|
|
63
|
-
#dispatch(buffer: Buffer): void {
|
63
|
+
#dispatch(buffer: Buffer<ArrayBuffer>): void {
|
64
64
|
assert(!this.#isClosed, '`PipeTransport` is closed.');
|
65
65
|
|
66
|
-
|
67
|
-
if (
|
68
|
-
this.#pendingMessage += buffer.toString();
|
66
|
+
this.#pendingMessage.push(buffer);
|
67
|
+
if (buffer.indexOf('\0') === -1) {
|
69
68
|
return;
|
70
69
|
}
|
71
|
-
const
|
72
|
-
setImmediate(() => {
|
73
|
-
if (this.onmessage) {
|
74
|
-
this.onmessage.call(null, message);
|
75
|
-
}
|
76
|
-
});
|
70
|
+
const concatBuffer = Buffer.concat(this.#pendingMessage);
|
77
71
|
|
78
|
-
let start =
|
79
|
-
end =
|
72
|
+
let start = 0;
|
73
|
+
let end = concatBuffer.indexOf('\0');
|
80
74
|
while (end !== -1) {
|
81
|
-
const message =
|
75
|
+
const message = concatBuffer.toString(undefined, start, end);
|
82
76
|
setImmediate(() => {
|
83
77
|
if (this.onmessage) {
|
84
78
|
this.onmessage.call(null, message);
|
85
79
|
}
|
86
80
|
});
|
87
81
|
start = end + 1;
|
88
|
-
end =
|
82
|
+
end = concatBuffer.indexOf('\0', start);
|
83
|
+
}
|
84
|
+
if (start >= concatBuffer.length) {
|
85
|
+
this.#pendingMessage = [];
|
86
|
+
} else {
|
87
|
+
this.#pendingMessage = [concatBuffer.subarray(start)];
|
89
88
|
}
|
90
|
-
this.#pendingMessage = buffer.toString(undefined, start);
|
91
89
|
}
|
92
90
|
|
93
91
|
close(): void {
|
@@ -8,7 +8,7 @@
|
|
8
8
|
* @internal
|
9
9
|
*/
|
10
10
|
export const PUPPETEER_REVISIONS = Object.freeze({
|
11
|
-
chrome: '140.0.7339.
|
12
|
-
'chrome-headless-shell': '140.0.7339.
|
13
|
-
firefox: 'stable_143.0',
|
11
|
+
chrome: '140.0.7339.207',
|
12
|
+
'chrome-headless-shell': '140.0.7339.207',
|
13
|
+
firefox: 'stable_143.0.1',
|
14
14
|
});
|
@@ -29,37 +29,29 @@ export const createFunction = (
|
|
29
29
|
*/
|
30
30
|
export function stringifyFunction(fn: (...args: never) => unknown): string {
|
31
31
|
let value = fn.toString();
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
`Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive`,
|
38
|
-
) ||
|
39
|
-
(err as Error).message.includes(
|
40
|
-
'Evaluating a string as JavaScript violates the following Content Security Policy',
|
41
|
-
)
|
42
|
-
) {
|
43
|
-
// The content security policy does not allow Function eval. Let's
|
44
|
-
// assume the value might be valid as is.
|
45
|
-
return value;
|
46
|
-
}
|
47
|
-
// This means we might have a function shorthand (e.g. `test(){}`). Let's
|
48
|
-
// try prefixing.
|
49
|
-
let prefix = 'function ';
|
50
|
-
if (value.startsWith('async ')) {
|
51
|
-
prefix = `async ${prefix}`;
|
52
|
-
value = value.substring('async '.length);
|
53
|
-
}
|
54
|
-
value = `${prefix}${value}`;
|
55
|
-
try {
|
56
|
-
new Function(`(${value})`);
|
57
|
-
} catch {
|
58
|
-
// We tried hard to serialize, but there's a weird beast here.
|
59
|
-
throw new Error('Passed function cannot be serialized!');
|
60
|
-
}
|
32
|
+
if (
|
33
|
+
value.match(/^(async )*function(\(|\s)/) ||
|
34
|
+
value.match(/^(async )*function\s*\*\s*/)
|
35
|
+
) {
|
36
|
+
return value;
|
61
37
|
}
|
62
|
-
|
38
|
+
const isArrow =
|
39
|
+
value.startsWith('(') ||
|
40
|
+
value.match(/^async\s*\(/) ||
|
41
|
+
value.match(
|
42
|
+
/^(async)*\s*(?:[$_\p{ID_Start}])(?:[$\u200C\u200D\p{ID_Continue}])*\s*=>/u,
|
43
|
+
);
|
44
|
+
if (isArrow) {
|
45
|
+
return value;
|
46
|
+
}
|
47
|
+
// This means we might have a function shorthand (e.g. `test(){}`). Let's
|
48
|
+
// try prefixing.
|
49
|
+
let prefix = 'function ';
|
50
|
+
if (value.startsWith('async ')) {
|
51
|
+
prefix = `async ${prefix}`;
|
52
|
+
value = value.substring('async '.length);
|
53
|
+
}
|
54
|
+
return `${prefix}${value}`;
|
63
55
|
}
|
64
56
|
|
65
57
|
/**
|
package/front_end/tsconfig.json
CHANGED
@@ -3,7 +3,18 @@
|
|
3
3
|
"compilerOptions": {
|
4
4
|
"allowUmdGlobalAccess": true,
|
5
5
|
"outDir": "ignored",
|
6
|
-
"
|
6
|
+
"target": "ES2023",
|
7
|
+
"lib": [
|
8
|
+
"ES2023",
|
9
|
+
"ES2024.Promise",
|
10
|
+
"ESNext.Iterator",
|
11
|
+
"ESNext.Collection",
|
12
|
+
"ESNext.Array",
|
13
|
+
"dom",
|
14
|
+
"dom.iterable",
|
15
|
+
"webworker",
|
16
|
+
"webworker.iterable"
|
17
|
+
],
|
7
18
|
"plugins": [
|
8
19
|
{
|
9
20
|
"name": "ts-lit-plugin",
|
@@ -704,7 +704,7 @@ export class Dialog extends HTMLElement {
|
|
704
704
|
return;
|
705
705
|
}
|
706
706
|
|
707
|
-
let dialogContent =
|
707
|
+
let dialogContent: Lit.LitTemplate = Lit.nothing;
|
708
708
|
|
709
709
|
// If state is expanded content should be shown, do not render it otherwise.
|
710
710
|
if (this.#props.state === DialogState.EXPANDED) {
|
@@ -24,7 +24,6 @@ export interface MarkdownImageData {
|
|
24
24
|
* This makes sure that all icons/images are accounted for in markdown.
|
25
25
|
*/
|
26
26
|
export class MarkdownImage extends HTMLElement {
|
27
|
-
|
28
27
|
readonly #shadow = this.attachShadow({mode: 'open'});
|
29
28
|
#imageData?: ImageData;
|
30
29
|
#imageTitle?: string;
|
@@ -37,9 +36,9 @@ export class MarkdownImage extends HTMLElement {
|
|
37
36
|
this.#render();
|
38
37
|
}
|
39
38
|
|
40
|
-
#getIconComponent(): Lit.
|
39
|
+
#getIconComponent(): Lit.LitTemplate {
|
41
40
|
if (!this.#imageData) {
|
42
|
-
return
|
41
|
+
return Lit.nothing;
|
43
42
|
}
|
44
43
|
const {src, color, width = '100%', height = '100%'} = this.#imageData;
|
45
44
|
return html`
|
@@ -47,9 +46,9 @@ export class MarkdownImage extends HTMLElement {
|
|
47
46
|
`;
|
48
47
|
}
|
49
48
|
|
50
|
-
#getImageComponent(): Lit.
|
49
|
+
#getImageComponent(): Lit.LitTemplate {
|
51
50
|
if (!this.#imageData) {
|
52
|
-
return
|
51
|
+
return Lit.nothing;
|
53
52
|
}
|
54
53
|
const {src, width = '100%', height = '100%'} = this.#imageData;
|
55
54
|
return html`
|
@@ -21,6 +21,7 @@ export class Switch extends HTMLElement {
|
|
21
21
|
#checked = false;
|
22
22
|
#disabled = false;
|
23
23
|
#jslogContext = '';
|
24
|
+
#label = '';
|
24
25
|
|
25
26
|
connectedCallback(): void {
|
26
27
|
this.#render();
|
@@ -53,6 +54,15 @@ export class Switch extends HTMLElement {
|
|
53
54
|
this.#render();
|
54
55
|
}
|
55
56
|
|
57
|
+
get label(): string {
|
58
|
+
return this.#label;
|
59
|
+
}
|
60
|
+
|
61
|
+
set label(label: string) {
|
62
|
+
this.#label = label;
|
63
|
+
this.#render();
|
64
|
+
}
|
65
|
+
|
56
66
|
#handleChange = (ev: Event): void => {
|
57
67
|
this.#checked = (ev.target as HTMLInputElement).checked;
|
58
68
|
this.dispatchEvent(new SwitchChangeEvent(this.#checked));
|
@@ -64,8 +74,9 @@ export class Switch extends HTMLElement {
|
|
64
74
|
// clang-format off
|
65
75
|
render(html`
|
66
76
|
<style>${switchStyles}</style>
|
67
|
-
<label
|
77
|
+
<label jslog=${jslog || nothing}>
|
68
78
|
<input type="checkbox"
|
79
|
+
aria-label=${this.#label || nothing}
|
69
80
|
@change=${this.#handleChange}
|
70
81
|
?disabled=${this.#disabled}
|
71
82
|
.checked=${this.#checked}
|
@@ -488,6 +488,7 @@ interface ActiveSuggestion {
|
|
488
488
|
rpcGlobalId?: Host.AidaClient.RpcGlobalId;
|
489
489
|
startTime: number;
|
490
490
|
onImpression: (rpcGlobalId: Host.AidaClient.RpcGlobalId, sampleId: number, latency: number) => void;
|
491
|
+
clearCachedRequest: () => void;
|
491
492
|
}
|
492
493
|
|
493
494
|
export const aiAutoCompleteSuggestionState = CM.StateField.define<ActiveSuggestion|null>({
|
@@ -498,6 +499,7 @@ export const aiAutoCompleteSuggestionState = CM.StateField.define<ActiveSuggesti
|
|
498
499
|
if (effect.value) {
|
499
500
|
return effect.value;
|
500
501
|
}
|
502
|
+
value?.clearCachedRequest();
|
501
503
|
return null;
|
502
504
|
}
|
503
505
|
}
|
@@ -509,13 +511,15 @@ export const aiAutoCompleteSuggestionState = CM.StateField.define<ActiveSuggesti
|
|
509
511
|
// A suggestion from an effect can be stale if the document was changed
|
510
512
|
// between when the request was sent and the response was received.
|
511
513
|
// We check if the position is still valid before trying to map it.
|
512
|
-
if (value.from > tr.
|
514
|
+
if (value.from > tr.state.doc.length) {
|
515
|
+
value.clearCachedRequest();
|
513
516
|
return null;
|
514
517
|
}
|
515
518
|
|
516
519
|
// If deletion occurs, set to null. Otherwise, the mapping might fail if
|
517
520
|
// the position is inside the deleted range.
|
518
521
|
if (tr.docChanged && tr.state.doc.length < tr.startState.doc.length) {
|
522
|
+
value.clearCachedRequest();
|
519
523
|
return null;
|
520
524
|
}
|
521
525
|
|
@@ -523,7 +527,8 @@ export const aiAutoCompleteSuggestionState = CM.StateField.define<ActiveSuggesti
|
|
523
527
|
const {head} = tr.state.selection.main;
|
524
528
|
|
525
529
|
// If a change happened before the position from which suggestion was generated, set to null.
|
526
|
-
if (head < from) {
|
530
|
+
if (tr.docChanged && head < from) {
|
531
|
+
value.clearCachedRequest();
|
527
532
|
return null;
|
528
533
|
}
|
529
534
|
|
@@ -563,6 +568,8 @@ export function acceptAiAutoCompleteSuggestion(view: CM.EditorView):
|
|
563
568
|
effects: setAiAutoCompleteSuggestion.of(null),
|
564
569
|
userEvent: 'input.complete',
|
565
570
|
});
|
571
|
+
|
572
|
+
suggestion.clearCachedRequest();
|
566
573
|
return {accepted: true, suggestion};
|
567
574
|
}
|
568
575
|
|
@@ -603,6 +610,13 @@ export const aiAutoCompleteSuggestion: CM.Extension = [
|
|
603
610
|
}
|
604
611
|
|
605
612
|
const {head} = update.state.selection.main;
|
613
|
+
// Hide AI suggestion if the user moves the cursor to a location
|
614
|
+
// before the position from which suggestion was generated.
|
615
|
+
if (head < activeSuggestion.from) {
|
616
|
+
this.decorations = CM.Decoration.none;
|
617
|
+
return;
|
618
|
+
}
|
619
|
+
|
606
620
|
const selectedCompletion = CM.selectedCompletion(update.state);
|
607
621
|
const additionallyTypedText = update.state.doc.sliceString(activeSuggestion.from, head);
|
608
622
|
// The user might have typed text after the suggestion is triggered.
|
@@ -18,7 +18,7 @@ import * as ARIAUtils from './ARIAUtils.js';
|
|
18
18
|
import type {Context} from './Context.js';
|
19
19
|
import type {ContextMenu} from './ContextMenu.js';
|
20
20
|
import {Dialog} from './Dialog.js';
|
21
|
-
import {DockController, DockState} from './DockController.js';
|
21
|
+
import {DockController, DockState, Events as DockControllerEvents} from './DockController.js';
|
22
22
|
import {GlassPane} from './GlassPane.js';
|
23
23
|
import {Infobar, Type as InfobarType} from './Infobar.js';
|
24
24
|
import {KeyboardShortcut} from './KeyboardShortcut.js';
|
@@ -127,8 +127,20 @@ export enum DrawerOrientation {
|
|
127
127
|
UNSET = 'unset',
|
128
128
|
}
|
129
129
|
|
130
|
+
export enum DockMode {
|
131
|
+
BOTTOM = 'bottom',
|
132
|
+
SIDE = 'side', // For LEFT and RIGHT
|
133
|
+
UNDOCKED = 'undocked',
|
134
|
+
}
|
135
|
+
|
136
|
+
export interface DrawerOrientationByDockMode {
|
137
|
+
[DockMode.BOTTOM]: DrawerOrientation;
|
138
|
+
[DockMode.SIDE]: DrawerOrientation;
|
139
|
+
[DockMode.UNDOCKED]: DrawerOrientation;
|
140
|
+
}
|
141
|
+
|
130
142
|
export class InspectorView extends VBox implements ViewLocationResolver {
|
131
|
-
private readonly
|
143
|
+
private readonly drawerOrientationByDockSetting: Common.Settings.Setting<DrawerOrientationByDockMode>;
|
132
144
|
private readonly drawerSplitWidget: SplitWidget;
|
133
145
|
private readonly tabDelegate: InspectorViewTabDelegate;
|
134
146
|
private readonly drawerTabbedLocation: TabbedViewLocation;
|
@@ -151,9 +163,14 @@ export class InspectorView extends VBox implements ViewLocationResolver {
|
|
151
163
|
this.setMinimumSize(MIN_INSPECTOR_WIDTH_HORIZONTAL_DRAWER, MIN_INSPECTOR_HEIGHT);
|
152
164
|
|
153
165
|
// DevTools sidebar is a vertical split of main tab bar panels and a drawer.
|
154
|
-
this.
|
155
|
-
Common.Settings.Settings.instance().createSetting('inspector.drawer-orientation',
|
156
|
-
|
166
|
+
this.drawerOrientationByDockSetting =
|
167
|
+
Common.Settings.Settings.instance().createSetting('inspector.drawer-orientation-by-dock-mode', {
|
168
|
+
[DockMode.BOTTOM]: DrawerOrientation.UNSET,
|
169
|
+
[DockMode.SIDE]: DrawerOrientation.UNSET,
|
170
|
+
[DockMode.UNDOCKED]: DrawerOrientation.UNSET,
|
171
|
+
});
|
172
|
+
const initialOrientation = this.#getOrientationForDockMode();
|
173
|
+
const isVertical = initialOrientation === DrawerOrientation.VERTICAL;
|
157
174
|
this.drawerSplitWidget = new SplitWidget(isVertical, true, 'inspector.drawer-split-view-state', 200, 200);
|
158
175
|
this.drawerSplitWidget.hideSidebar();
|
159
176
|
this.drawerSplitWidget.enableShowModeSaving();
|
@@ -285,6 +302,50 @@ export class InspectorView extends VBox implements ViewLocationResolver {
|
|
285
302
|
inspectorViewInstance = null;
|
286
303
|
}
|
287
304
|
|
305
|
+
onDockSideChangedHandledForTest(): void {
|
306
|
+
}
|
307
|
+
|
308
|
+
#onDockSideChanged(): void {
|
309
|
+
if (!this.drawerVisible()) {
|
310
|
+
this.onDockSideChangedHandledForTest();
|
311
|
+
return;
|
312
|
+
}
|
313
|
+
const newOrientation = this.#getOrientationForDockMode();
|
314
|
+
this.#applyOrientation(newOrientation);
|
315
|
+
this.onDockSideChangedHandledForTest();
|
316
|
+
}
|
317
|
+
|
318
|
+
#getDockMode(): DockMode {
|
319
|
+
const dockSide = DockController.instance().dockSide();
|
320
|
+
if (dockSide === DockState.BOTTOM) {
|
321
|
+
return DockMode.BOTTOM;
|
322
|
+
}
|
323
|
+
if (dockSide === DockState.UNDOCKED) {
|
324
|
+
return DockMode.UNDOCKED;
|
325
|
+
}
|
326
|
+
|
327
|
+
return DockMode.SIDE;
|
328
|
+
}
|
329
|
+
|
330
|
+
#getOrientationForDockMode(): Omit<DrawerOrientation, DrawerOrientation.UNSET> {
|
331
|
+
const dockMode = this.#getDockMode();
|
332
|
+
const orientationSetting = this.drawerOrientationByDockSetting.get();
|
333
|
+
|
334
|
+
let orientation = orientationSetting[dockMode];
|
335
|
+
if (orientation === DrawerOrientation.UNSET) {
|
336
|
+
// Apply defaults: horizontal for side-dock, vertical for bottom-dock.
|
337
|
+
orientation = dockMode === DockMode.BOTTOM ? DrawerOrientation.VERTICAL : DrawerOrientation.HORIZONTAL;
|
338
|
+
}
|
339
|
+
return orientation;
|
340
|
+
}
|
341
|
+
|
342
|
+
#applyOrientation(orientation: Omit<DrawerOrientation, DrawerOrientation.UNSET>): void {
|
343
|
+
const isVertical = orientation === DrawerOrientation.VERTICAL;
|
344
|
+
this.#toggleOrientationButton.setGlyph(isVertical ? 'dock-bottom' : 'dock-right');
|
345
|
+
this.drawerSplitWidget.setVertical(isVertical);
|
346
|
+
this.setDrawerRelatedMinimumSizes();
|
347
|
+
}
|
348
|
+
|
288
349
|
#observedResize(): void {
|
289
350
|
const rect = this.element.getBoundingClientRect();
|
290
351
|
this.element.style.setProperty('--devtools-window-left', `${rect.left}px`);
|
@@ -299,11 +360,15 @@ export class InspectorView extends VBox implements ViewLocationResolver {
|
|
299
360
|
this.#resizeObserver.observe(this.element);
|
300
361
|
this.#observedResize();
|
301
362
|
this.element.ownerDocument.addEventListener('keydown', this.keyDownBound, false);
|
363
|
+
DockController.instance().addEventListener(DockControllerEvents.DOCK_SIDE_CHANGED, this.#onDockSideChanged, this);
|
364
|
+
this.#onDockSideChanged();
|
302
365
|
}
|
303
366
|
|
304
367
|
override willHide(): void {
|
305
368
|
this.#resizeObserver.unobserve(this.element);
|
306
369
|
this.element.ownerDocument.removeEventListener('keydown', this.keyDownBound, false);
|
370
|
+
DockController.instance().removeEventListener(
|
371
|
+
DockControllerEvents.DOCK_SIDE_CHANGED, this.#onDockSideChanged, this);
|
307
372
|
}
|
308
373
|
|
309
374
|
resolveLocation(locationName: string): ViewLocation|null {
|
@@ -421,21 +486,29 @@ export class InspectorView extends VBox implements ViewLocationResolver {
|
|
421
486
|
if (!this.drawerTabbedPane.isShowing()) {
|
422
487
|
return;
|
423
488
|
}
|
424
|
-
|
489
|
+
|
490
|
+
const dockMode = this.#getDockMode();
|
491
|
+
const currentSettings = this.drawerOrientationByDockSetting.get();
|
492
|
+
|
493
|
+
let newOrientation: Omit<DrawerOrientation, DrawerOrientation.UNSET>;
|
425
494
|
if (force) {
|
426
|
-
|
495
|
+
newOrientation = force;
|
427
496
|
} else {
|
428
|
-
|
497
|
+
const currentOrientation = this.#getOrientationForDockMode();
|
498
|
+
newOrientation =
|
499
|
+
currentOrientation === DrawerOrientation.VERTICAL ? DrawerOrientation.HORIZONTAL : DrawerOrientation.VERTICAL;
|
429
500
|
}
|
430
501
|
|
431
|
-
|
432
|
-
this
|
433
|
-
|
434
|
-
this
|
502
|
+
currentSettings[dockMode] = newOrientation as DrawerOrientation;
|
503
|
+
this.drawerOrientationByDockSetting.set(currentSettings);
|
504
|
+
|
505
|
+
this.#applyOrientation(newOrientation);
|
435
506
|
}
|
436
507
|
|
437
508
|
isUserExplicitlyUpdatedDrawerOrientation(): boolean {
|
438
|
-
|
509
|
+
const orientationSetting = this.drawerOrientationByDockSetting.get();
|
510
|
+
const dockMode = this.#getDockMode();
|
511
|
+
return orientationSetting[dockMode] !== DrawerOrientation.UNSET;
|
439
512
|
}
|
440
513
|
|
441
514
|
setDrawerRelatedMinimumSizes(): void {
|
@@ -326,6 +326,8 @@ export class TabbedPane extends Common.ObjectWrapper.eventMixin<EventTypes, type
|
|
326
326
|
return false;
|
327
327
|
}
|
328
328
|
|
329
|
+
this.lastSelectedOverflowTab = tab;
|
330
|
+
|
329
331
|
const eventData: EventData = {
|
330
332
|
prevTabId: this.currentTab ? this.currentTab.id : undefined,
|
331
333
|
tabId: id,
|
@@ -676,7 +678,6 @@ export class TabbedPane extends Common.ObjectWrapper.eventMixin<EventTypes, type
|
|
676
678
|
}
|
677
679
|
|
678
680
|
private dropDownMenuItemSelected(tab: TabbedPaneTab): void {
|
679
|
-
this.lastSelectedOverflowTab = tab;
|
680
681
|
this.selectTab(tab.id, true, true);
|
681
682
|
}
|
682
683
|
|
@@ -1455,7 +1455,7 @@ export class TreeSearch < NodeT extends TreeNode<NodeT>,
|
|
1455
1455
|
return this.#getNodeMatchMap().get(node) ?? [];
|
1456
1456
|
}
|
1457
1457
|
|
1458
|
-
highlight(ranges: TextUtils.TextRange.SourceRange[], selectedRange: TextUtils.TextRange.SourceRange|undefined):
|
1458
|
+
static highlight(ranges: TextUtils.TextRange.SourceRange[], selectedRange: TextUtils.TextRange.SourceRange|undefined):
|
1459
1459
|
ReturnType<typeof Lit.Directives.ref> {
|
1460
1460
|
return Lit.Directives.ref(element => {
|
1461
1461
|
if (element instanceof HTMLLIElement) {
|
@@ -1777,6 +1777,8 @@ export class TreeViewElement extends HTMLElementWithLightDOMTemplate {
|
|
1777
1777
|
const nextElement = nextSibling ? TreeViewTreeElement.get(nextSibling) : null;
|
1778
1778
|
const index = nextElement ? parent.treeElement.indexOfChild(nextElement) : parent.treeElement.children().length;
|
1779
1779
|
const treeElement = new TreeViewTreeElement(this.#treeOutline, node);
|
1780
|
+
const expandable = Boolean(node.querySelector('ul[role="group"]'));
|
1781
|
+
treeElement.setExpandable(expandable);
|
1780
1782
|
parent.treeElement.insertChild(treeElement, index);
|
1781
1783
|
if (hasBooleanAttribute(node, 'selected')) {
|
1782
1784
|
treeElement.revealAndSelect(true);
|
@@ -129,7 +129,7 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
129
129
|
}
|
130
130
|
}
|
131
131
|
}
|
132
|
-
return
|
132
|
+
return UI.TreeOutline.TreeSearch.highlight(highlights, selected);
|
133
133
|
}
|
134
134
|
|
135
135
|
function layOutNode(node: XMLTreeViewNode, populateSubtrees = false): Lit.LitTemplate {
|
@@ -138,13 +138,15 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
138
138
|
|
139
139
|
// clang-format off
|
140
140
|
return html`
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
141
|
+
<li ${highlight(node, /* closeTag=*/ false)} role="treeitem"
|
142
|
+
?selected=${input.jumpToNextSearchResult?.node === node}
|
143
|
+
@expand=${onExpand}>
|
144
|
+
${htmlView(node)}
|
145
|
+
${node.children().length ? html`
|
146
|
+
<ul role="group" ?hidden=${!node.expanded}>
|
147
|
+
${populateSubtrees || input.search ? subtree(node) : Lit.nothing}
|
148
|
+
</ul>` : Lit.nothing}
|
149
|
+
</li>`;
|
148
150
|
// clang-format on
|
149
151
|
}
|
150
152
|
|
@@ -154,15 +156,14 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
154
156
|
return Lit.nothing;
|
155
157
|
}
|
156
158
|
// clang-format off
|
157
|
-
return html
|
159
|
+
return html`
|
158
160
|
${children.map(child => layOutNode(child, treeNode.expanded))}
|
159
161
|
${treeNode.node instanceof Element
|
160
162
|
? html`<li
|
161
163
|
${highlight(treeNode, /* closeTag=*/ true)}
|
162
164
|
role="treeitem"><span part='shadow-xml-view-close-tag'>${'</' + treeNode.node.tagName + '>'}</span
|
163
165
|
></li>`
|
164
|
-
: Lit.nothing}
|
165
|
-
</ul>`;
|
166
|
+
: Lit.nothing}`;
|
166
167
|
// clang-format on
|
167
168
|
}
|
168
169
|
|
@@ -2,6 +2,9 @@
|
|
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
|
+
// This files is import lit directly
|
6
|
+
/* eslint-disable rulesdir/lit-template-result-or-nothing */
|
7
|
+
|
5
8
|
import * as i18n from '../../core/i18n/i18n.js';
|
6
9
|
import type * as I18n from '../../third_party/i18n/i18n.js';
|
7
10
|
import * as Lit from '../../third_party/lit/lit.js';
|
@@ -14,10 +17,10 @@ const {html} = Lit.StaticHtml;
|
|
14
17
|
*/
|
15
18
|
export function i18nTemplate(
|
16
19
|
registeredStrings: I18n.LocalizedStringSet.RegisteredFileStrings, stringId: string,
|
17
|
-
placeholders: Record<string, Lit.TemplateResult|string>): Lit.TemplateResult {
|
20
|
+
placeholders: Record<string, Lit.TemplateResult|string>): Lit.TemplateResult|typeof Lit.nothing {
|
18
21
|
const formatter = registeredStrings.getLocalizedStringSetFor(i18n.DevToolsLocale.DevToolsLocale.instance().locale)
|
19
22
|
.getMessageFormatterFor(stringId);
|
20
|
-
let result =
|
23
|
+
let result: Lit.TemplateResult|typeof Lit.nothing = Lit.nothing;
|
21
24
|
for (const icuElement of formatter.getAst()) {
|
22
25
|
if (icuElement.type === /* argumentElement */ 1) {
|
23
26
|
const placeholderValue = placeholders[icuElement.value];
|