chrome-devtools-frontend 1.0.1516909 → 1.0.1519267
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 +2 -2
- package/docs/checklist/README.md +2 -2
- package/docs/checklist/javascript.md +1 -1
- package/docs/contributing/README.md +1 -1
- package/docs/contributing/settings-experiments-features.md +9 -8
- package/docs/cookbook/devtools_on_devtools.md +2 -2
- package/docs/cookbook/localization.md +10 -10
- package/docs/devtools-protocol.md +9 -8
- package/docs/ecosystem/automatic_workspace_folders.md +3 -3
- package/docs/get_the_code.md +0 -2
- package/docs/styleguide/ux/components.md +166 -85
- package/docs/styleguide/ux/numbers.md +3 -4
- package/eslint.config.mjs +1 -0
- package/front_end/core/common/README.md +13 -12
- package/front_end/core/host/GdpClient.ts +16 -1
- package/front_end/core/host/UserMetrics.ts +4 -2
- package/front_end/core/root/Runtime.ts +13 -0
- package/front_end/core/sdk/CSSMatchedStyles.ts +5 -1
- package/front_end/core/sdk/EnhancedTracesParser.ts +5 -5
- 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 -3
- package/front_end/generated/InspectorBackendCommands.js +10 -7
- package/front_end/generated/SupportedCSSProperties.js +40 -11
- package/front_end/generated/protocol-mapping.d.ts +16 -1
- package/front_end/generated/protocol-proxy-api.d.ts +13 -1
- package/front_end/generated/protocol.ts +95 -0
- package/front_end/models/ai_assistance/agents/AiAgent.ts +57 -10
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +119 -51
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +0 -31
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +14 -181
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +19 -315
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +224 -50
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +310 -11
- package/front_end/models/ai_assistance/performance/AIContext.ts +15 -2
- package/front_end/models/ai_code_completion/AiCodeCompletion.ts +22 -11
- package/front_end/models/badges/AiExplorerBadge.ts +19 -3
- package/front_end/models/badges/Badge.ts +10 -3
- package/front_end/models/badges/CodeWhispererBadge.ts +3 -4
- 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 +3 -2
- package/front_end/models/badges/UserBadges.ts +21 -3
- package/front_end/models/badges/badges.ts +1 -0
- package/front_end/models/javascript_metadata/NativeFunctions.js +2 -2
- package/front_end/models/trace/EventsSerializer.ts +4 -3
- package/front_end/models/trace/README.md +28 -1
- package/front_end/models/trace/handlers/UserInteractionsHandler.ts +101 -73
- package/front_end/models/trace/handlers/UserTimingsHandler.ts +1 -1
- package/front_end/models/trace/helpers/Timing.ts +1 -1
- package/front_end/models/trace/helpers/Trace.ts +99 -43
- package/front_end/models/trace/types/TraceEvents.ts +9 -0
- package/front_end/panels/accessibility/ARIAAttributesView.ts +113 -191
- package/front_end/panels/accessibility/AccessibilityNodeView.ts +9 -9
- package/front_end/panels/accessibility/AccessibilitySubPane.ts +6 -4
- package/front_end/panels/accessibility/accessibilityProperties.css +2 -0
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +20 -3
- package/front_end/panels/ai_assistance/components/ChatView.ts +9 -10
- package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +44 -0
- package/front_end/panels/application/components/BounceTrackingMitigationsView.ts +2 -2
- package/front_end/panels/common/AiCodeCompletionDisclaimer.ts +32 -9
- package/front_end/panels/common/AiCodeCompletionSummaryToolbar.ts +7 -1
- package/front_end/panels/common/BadgeNotification.ts +21 -5
- package/front_end/panels/common/GdpSignUpDialog.ts +20 -12
- package/front_end/panels/console/ConsolePrompt.ts +1 -1
- package/front_end/panels/console/ConsoleView.ts +6 -2
- package/front_end/panels/css_overview/CSSOverviewCompletedView.ts +5 -5
- package/front_end/panels/elements/ElementsPanel.ts +4 -0
- package/front_end/panels/elements/ElementsTreeElement.ts +18 -0
- package/front_end/panels/elements/ElementsTreeOutline.ts +13 -0
- package/front_end/panels/elements/StylePropertyTreeElement.ts +21 -6
- package/front_end/panels/media/TickingFlameChart.ts +1 -1
- package/front_end/panels/profiler/HeapSnapshotView.ts +34 -19
- package/front_end/panels/recorder/components/RecordingView.ts +2 -2
- package/front_end/panels/search/SearchResultsPane.ts +167 -152
- package/front_end/panels/search/SearchView.ts +36 -26
- package/front_end/panels/search/searchResultsPane.css +9 -0
- 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 +39 -17
- package/front_end/panels/settings/emulation/components/UserAgentClientHintsForm.ts +1 -1
- package/front_end/panels/sources/AiCodeCompletionPlugin.ts +9 -1
- package/front_end/panels/sources/SourcesPanel.ts +4 -1
- package/front_end/panels/sources/sourcesView.css +6 -1
- package/front_end/panels/timeline/AppenderUtils.ts +2 -2
- package/front_end/panels/timeline/ExtensionTrackAppender.ts +13 -4
- package/front_end/panels/timeline/GPUTrackAppender.ts +2 -1
- package/front_end/panels/timeline/InteractionsTrackAppender.ts +5 -1
- package/front_end/panels/timeline/LayoutShiftsTrackAppender.ts +2 -1
- package/front_end/panels/timeline/ThreadAppender.ts +12 -3
- package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +9 -4
- package/front_end/panels/timeline/TimelinePanel.ts +3 -2
- package/front_end/panels/timeline/TimelineUIUtils.ts +5 -4
- package/front_end/panels/timeline/TimingsTrackAppender.ts +6 -1
- package/front_end/panels/timeline/components/CPUThrottlingSelector.ts +95 -82
- package/front_end/panels/timeline/components/LayoutShiftDetails.ts +1 -1
- package/front_end/panels/timeline/components/LiveMetricsView.ts +2 -2
- 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/panels/timeline/components/cpuThrottlingSelector.css +17 -15
- package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +3 -0
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/codemirror.next/chunk/codemirror.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/codemirror.js.map +1 -1
- package/front_end/third_party/codemirror.next/codemirror.next.d.ts +6 -9
- package/front_end/third_party/codemirror.next/package.json +2 -1
- package/front_end/third_party/diff/README.chromium +1 -0
- 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/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/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/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/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 +10 -3
- 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/ChromeLauncher.ts +1 -0
- 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/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 +22 -9
- package/front_end/ui/components/tooltips/Tooltip.ts +70 -31
- package/front_end/ui/legacy/README.md +33 -24
- package/front_end/ui/legacy/SearchableView.ts +19 -26
- package/front_end/ui/legacy/TextPrompt.ts +166 -1
- package/front_end/ui/legacy/Treeoutline.ts +19 -3
- package/front_end/ui/legacy/UIUtils.ts +15 -2
- package/front_end/ui/legacy/XElement.ts +0 -43
- package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +20 -4
- 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 +23 -6
- package/front_end/ui/visual_logging/README.md +43 -27
- package/package.json +1 -1
@@ -303,7 +303,17 @@ export class HeapSnapshotView extends UI.View.SimpleView implements DataDisplayD
|
|
303
303
|
baseProfile!: HeapProfileHeader|null;
|
304
304
|
trackingOverviewGrid?: HeapTimelineOverview;
|
305
305
|
currentSearchResultIndex = -1;
|
306
|
-
|
306
|
+
currentSearch?: HeapSnapshotModel.HeapSnapshotModel.SearchConfig;
|
307
|
+
|
308
|
+
get currentQuery(): string|undefined {
|
309
|
+
return this.currentSearch?.query;
|
310
|
+
}
|
311
|
+
set currentQuery(value: string) {
|
312
|
+
if (this.currentSearch) {
|
313
|
+
this.currentSearch.query = value;
|
314
|
+
}
|
315
|
+
}
|
316
|
+
|
307
317
|
constructor(dataDisplayDelegate: DataDisplayDelegate, profile: HeapProfileHeader) {
|
308
318
|
super({
|
309
319
|
title: i18nString(UIStrings.heapSnapshot),
|
@@ -643,8 +653,13 @@ export class HeapSnapshotView extends UI.View.SimpleView implements DataDisplayD
|
|
643
653
|
|
644
654
|
performSearch(searchConfig: UI.SearchableView.SearchConfig, shouldJump: boolean, jumpBackwards?: boolean): void {
|
645
655
|
const nextQuery = new HeapSnapshotModel.HeapSnapshotModel.SearchConfig(
|
646
|
-
searchConfig.query.trim(),
|
647
|
-
|
656
|
+
searchConfig.query.trim(),
|
657
|
+
searchConfig.caseSensitive,
|
658
|
+
searchConfig.wholeWord,
|
659
|
+
searchConfig.isRegex,
|
660
|
+
shouldJump,
|
661
|
+
jumpBackwards || false,
|
662
|
+
);
|
648
663
|
|
649
664
|
void this.searchThrottler.schedule(this.performSearchInternal.bind(this, nextQuery));
|
650
665
|
}
|
@@ -657,7 +672,7 @@ export class HeapSnapshotView extends UI.View.SimpleView implements DataDisplayD
|
|
657
672
|
return;
|
658
673
|
}
|
659
674
|
|
660
|
-
this.
|
675
|
+
this.currentSearch = nextQuery;
|
661
676
|
const query = nextQuery.query.trim();
|
662
677
|
|
663
678
|
if (!query) {
|
@@ -682,7 +697,7 @@ export class HeapSnapshotView extends UI.View.SimpleView implements DataDisplayD
|
|
682
697
|
}
|
683
698
|
|
684
699
|
const filter = this.dataGrid.nodeFilter();
|
685
|
-
this.searchResults = filter ? await this.profile.snapshotProxy.search(this.
|
700
|
+
this.searchResults = filter ? await this.profile.snapshotProxy.search(this.currentSearch, filter) : [];
|
686
701
|
|
687
702
|
this.searchableViewInternal.updateSearchMatchesCount(this.searchResults.length);
|
688
703
|
if (this.searchResults.length) {
|
@@ -724,10 +739,10 @@ export class HeapSnapshotView extends UI.View.SimpleView implements DataDisplayD
|
|
724
739
|
if (!this.dataGrid) {
|
725
740
|
return;
|
726
741
|
}
|
727
|
-
let child:
|
742
|
+
let child: DataGrid.DataGrid.DataGridNode<HeapSnapshotGridNode>|null = this.dataGrid.rootNode().children[0];
|
728
743
|
while (child) {
|
729
744
|
child.refresh();
|
730
|
-
child =
|
745
|
+
child = child.traverseNextNode(false, null, true);
|
731
746
|
}
|
732
747
|
}
|
733
748
|
|
@@ -735,28 +750,28 @@ export class HeapSnapshotView extends UI.View.SimpleView implements DataDisplayD
|
|
735
750
|
if (this.baseProfile === this.profiles()[this.baseSelect.selectedIndex()]) {
|
736
751
|
return;
|
737
752
|
}
|
738
|
-
this.baseProfile =
|
753
|
+
this.baseProfile = this.profiles()[this.baseSelect.selectedIndex()];
|
739
754
|
const dataGrid = (this.dataGrid as HeapSnapshotDiffDataGrid);
|
740
755
|
// Change set base data source only if main data source is already set.
|
741
756
|
if (dataGrid.snapshot) {
|
742
757
|
void this.baseProfile.loadPromise.then(dataGrid.setBaseDataSource.bind(dataGrid));
|
743
758
|
}
|
744
759
|
|
745
|
-
if (!this.
|
760
|
+
if (!this.currentSearch || !this.searchResults) {
|
746
761
|
return;
|
747
762
|
}
|
748
763
|
|
749
764
|
// The current search needs to be performed again. First negate out previous match
|
750
765
|
// count by calling the search finished callback with a negative number of matches.
|
751
766
|
// Then perform the search again with the same query and callback.
|
752
|
-
this.performSearch(this.
|
767
|
+
this.performSearch(this.currentSearch, false);
|
753
768
|
}
|
754
769
|
|
755
|
-
static readonly ALWAYS_AVAILABLE_FILTERS = [
|
770
|
+
static readonly ALWAYS_AVAILABLE_FILTERS: ReadonlyArray<{uiName: string, filterName: string}> = [
|
756
771
|
{uiName: i18nString(UIStrings.duplicatedStrings), filterName: 'duplicatedStrings'},
|
757
772
|
{uiName: i18nString(UIStrings.objectsRetainedByDetachedDomNodes), filterName: 'objectsRetainedByDetachedDomNodes'},
|
758
773
|
{uiName: i18nString(UIStrings.objectsRetainedByConsole), filterName: 'objectsRetainedByConsole'},
|
759
|
-
]
|
774
|
+
];
|
760
775
|
|
761
776
|
changeFilter(): void {
|
762
777
|
let selectedIndex = this.filterSelect.selectedIndex();
|
@@ -773,19 +788,19 @@ export class HeapSnapshotView extends UI.View.SimpleView implements DataDisplayD
|
|
773
788
|
return;
|
774
789
|
}
|
775
790
|
(this.dataGrid as HeapSnapshotConstructorsDataGrid)
|
776
|
-
.filterSelectIndexChanged(
|
791
|
+
.filterSelectIndexChanged(this.profiles(), profileIndex, filterName);
|
777
792
|
|
778
|
-
if (!this.
|
793
|
+
if (!this.currentSearch || !this.searchResults) {
|
779
794
|
return;
|
780
795
|
}
|
781
796
|
|
782
797
|
// The current search needs to be performed again. First negate out previous match
|
783
798
|
// count by calling the search finished callback with a negative number of matches.
|
784
799
|
// Then perform the search again with the same query and callback.
|
785
|
-
this.performSearch(this.
|
800
|
+
this.performSearch(this.currentSearch, false);
|
786
801
|
}
|
787
802
|
|
788
|
-
profiles():
|
803
|
+
profiles(): HeapProfileHeader[] {
|
789
804
|
return this.profile.profileType().getProfiles();
|
790
805
|
}
|
791
806
|
|
@@ -866,7 +881,7 @@ export class HeapSnapshotView extends UI.View.SimpleView implements DataDisplayD
|
|
866
881
|
return;
|
867
882
|
}
|
868
883
|
if (!this.baseProfile) {
|
869
|
-
this.baseProfile =
|
884
|
+
this.baseProfile = this.profiles()[this.baseSelect.selectedIndex()];
|
870
885
|
}
|
871
886
|
|
872
887
|
const baseSnapshotProxy = await this.baseProfile.loadPromise;
|
@@ -900,14 +915,14 @@ export class HeapSnapshotView extends UI.View.SimpleView implements DataDisplayD
|
|
900
915
|
|
901
916
|
void this.updateDataSourceAndView();
|
902
917
|
|
903
|
-
if (!this.
|
918
|
+
if (!this.currentSearch || !this.searchResults) {
|
904
919
|
return;
|
905
920
|
}
|
906
921
|
|
907
922
|
// The current search needs to be performed again. First negate out previous match
|
908
923
|
// count by calling the search finished callback with a negative number of matches.
|
909
924
|
// Then perform the search again the with same query and callback.
|
910
|
-
this.performSearch(this.
|
925
|
+
this.performSearch(this.currentSearch, false);
|
911
926
|
}
|
912
927
|
|
913
928
|
async selectLiveObject(perspectiveName: string, snapshotObjectId: string): Promise<void> {
|
@@ -220,9 +220,9 @@ function renderSettings({
|
|
220
220
|
replayState,
|
221
221
|
onReplaySettingsKeydown,
|
222
222
|
onToggleReplaySettings
|
223
|
-
}: ViewInput): Lit.
|
223
|
+
}: ViewInput): Lit.LitTemplate {
|
224
224
|
if (!settings) {
|
225
|
-
return
|
225
|
+
return Lit.nothing;
|
226
226
|
}
|
227
227
|
const environmentFragments = [];
|
228
228
|
if (settings.viewportSettings) {
|
@@ -1,16 +1,13 @@
|
|
1
1
|
// Copyright 2014 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
|
-
/* eslint-disable rulesdir/no-lit-render-outside-of-view */
|
6
|
-
|
7
4
|
import * as Common from '../../core/common/common.js';
|
8
5
|
import * as i18n from '../../core/i18n/i18n.js';
|
9
6
|
import * as Platform from '../../core/platform/platform.js';
|
10
7
|
import * as TextUtils from '../../models/text_utils/text_utils.js';
|
11
8
|
import type * as Workspace from '../../models/workspace/workspace.js';
|
12
9
|
import * as UI from '../../ui/legacy/legacy.js';
|
13
|
-
import {html, render} from '../../ui/lit/lit.js';
|
10
|
+
import {html, render, type TemplateResult} from '../../ui/lit/lit.js';
|
14
11
|
|
15
12
|
import searchResultsPaneStyles from './searchResultsPane.css.js';
|
16
13
|
import type {SearchResult} from './SearchScope.js';
|
@@ -35,136 +32,175 @@ const UIStrings = {
|
|
35
32
|
const str_ = i18n.i18n.registerUIStrings('panels/search/SearchResultsPane.ts', UIStrings);
|
36
33
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
37
34
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
private matchesExpandedCount: number;
|
35
|
+
interface SearchMatch {
|
36
|
+
lineContent: string;
|
37
|
+
matchRanges: TextUtils.TextRange.SourceRange[];
|
38
|
+
resultLabel: string|number;
|
39
|
+
}
|
44
40
|
|
45
|
-
|
46
|
-
|
47
|
-
|
41
|
+
interface ViewInput {
|
42
|
+
results: SearchResult[];
|
43
|
+
matches: WeakMap<SearchResult, SearchMatch[]>;
|
44
|
+
expandedResults: WeakSet<SearchResult>;
|
45
|
+
onSelectMatch: (searchResult: SearchResult, matchIndex: number) => void;
|
46
|
+
onExpandSearchResult: (searchResult: SearchResult) => void;
|
47
|
+
onShowMoreMatches: (searchResult: SearchResult) => void;
|
48
|
+
}
|
48
49
|
|
49
|
-
|
50
|
-
this.treeElements = [];
|
51
|
-
this.treeOutline = new UI.TreeOutline.TreeOutlineInShadow();
|
52
|
-
this.treeOutline.registerRequiredCSS(searchResultsPaneStyles);
|
53
|
-
this.treeOutline.setHideOverflow(true);
|
50
|
+
export type View = (input: ViewInput, output: unknown, target: HTMLElement) => void;
|
54
51
|
|
55
|
-
|
52
|
+
export const DEFAULT_VIEW: View = (input, _output, target) => {
|
53
|
+
const {results, matches, expandedResults, onSelectMatch, onExpandSearchResult, onShowMoreMatches} = input;
|
56
54
|
|
57
|
-
|
58
|
-
|
55
|
+
const onExpand = ({detail: {expanded, target}}: UI.TreeOutline.TreeViewElement.ExpandEvent): void => {
|
56
|
+
const searchResultIndex = Number(target.dataset.searchResultIndex);
|
57
|
+
const searchResult = results[searchResultIndex];
|
58
|
+
if (expanded) {
|
59
|
+
expandedResults.add(searchResult);
|
60
|
+
onExpandSearchResult(searchResult);
|
61
|
+
} else {
|
62
|
+
expandedResults.delete(searchResult);
|
63
|
+
}
|
64
|
+
};
|
65
|
+
|
66
|
+
// clang-format off
|
67
|
+
render(html`
|
68
|
+
<devtools-tree hide-overflow @expand=${onExpand} .template=${html`
|
69
|
+
<ul role="tree">
|
70
|
+
${results.map((searchResult, i) => html`
|
71
|
+
<li role="treeitem" data-search-result-index=${i} class="search-result">
|
72
|
+
<style>${searchResultsPaneStyles}</style>
|
73
|
+
${renderSearchResult(searchResult)}
|
74
|
+
<ul role="group" ?hidden=${!expandedResults.has(searchResult)}>
|
75
|
+
${renderSearchMatches(searchResult, matches, onSelectMatch, onShowMoreMatches)}
|
76
|
+
</ul>
|
77
|
+
</li>`)}
|
78
|
+
</ul>
|
79
|
+
`}></devtools-tree>`,
|
80
|
+
target,
|
81
|
+
);
|
82
|
+
// clang-format on
|
83
|
+
};
|
59
84
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
85
|
+
const renderSearchResult = (searchResult: SearchResult): TemplateResult => {
|
86
|
+
// clang-format off
|
87
|
+
return html`
|
88
|
+
<span class="search-result-file-name">${searchResult.label()}
|
89
|
+
<span class="search-result-dash">${'\u2014'}</span>
|
90
|
+
<span class="search-result-qualifier">${searchResult.description()}</span>
|
91
|
+
</span>
|
92
|
+
<span class="search-result-matches-count"
|
93
|
+
aria-label=${i18nString(UIStrings.matchesCountS, {PH1: searchResult.matchesCount()})}>
|
94
|
+
${searchResult.matchesCount()}
|
95
|
+
</span>`;
|
96
|
+
// clang-format on
|
97
|
+
};
|
64
98
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
99
|
+
const renderSearchMatches =
|
100
|
+
(searchResult: SearchResult, matches: WeakMap<SearchResult, SearchMatch[]>,
|
101
|
+
onSelectMatch: (searchResult: SearchResult, matchIndex: number) => void,
|
102
|
+
onShowMoreMatches: (searchResult: SearchResult) => void): TemplateResult => {
|
103
|
+
const visibleMatches = matches.get(searchResult) ?? [];
|
104
|
+
const matchesLeftCount = searchResult.matchesCount() - visibleMatches.length;
|
105
|
+
// clang-format off
|
106
|
+
return html`
|
107
|
+
${visibleMatches.map(({lineContent, matchRanges, resultLabel}, i) => html`
|
108
|
+
<li role="treeitem" class="search-match" @click=${() => onSelectMatch(searchResult, i)}
|
109
|
+
${UI.TreeOutline.TreeSearch.highlight(matchRanges.map(range =>
|
110
|
+
({offset: range.offset + `${resultLabel}`.length, length: range.length})), undefined)}
|
111
|
+
@keydown=${(event: KeyboardEvent) => {
|
112
|
+
if (event.key === 'Enter') {
|
113
|
+
onSelectMatch(searchResult, i);
|
114
|
+
}
|
115
|
+
}}
|
116
|
+
>
|
117
|
+
<button class="devtools-link text-button link-style search-match-link"
|
118
|
+
jslog="Link; context: search-match; track: click" role="link" tabindex="0"
|
119
|
+
@click=${() => void Common.Revealer.reveal(searchResult.matchRevealable(i))}>
|
120
|
+
<span class="search-match-line-number"
|
121
|
+
aria-label=${typeof resultLabel === 'number' && !isNaN(resultLabel)
|
122
|
+
? i18nString(UIStrings.lineS, {PH1: resultLabel}) : resultLabel}>
|
123
|
+
${resultLabel}
|
124
|
+
</span>
|
125
|
+
<span class="search-match-content" aria-label="${lineContent} line">
|
126
|
+
${lineContent}
|
127
|
+
</span>
|
128
|
+
</button>
|
129
|
+
</li>`)}
|
130
|
+
${
|
131
|
+
matchesLeftCount > 0 ? html`
|
132
|
+
<li role="treeitem" class="show-more-matches" @click=${() => onShowMoreMatches(searchResult)}>
|
133
|
+
${i18nString(UIStrings.showDMore, { PH1: matchesLeftCount })}
|
134
|
+
</li>` : ''}`;
|
135
|
+
// clang-format on
|
136
|
+
};
|
71
137
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
138
|
+
export class SearchResultsPane extends UI.Widget.VBox {
|
139
|
+
readonly #searchConfig: Workspace.SearchConfig.SearchConfig;
|
140
|
+
#searchResults: SearchResult[] = [];
|
141
|
+
#expandedResults = new WeakSet<SearchResult>();
|
142
|
+
readonly #searchMatches = new WeakMap<SearchResult, SearchMatch[]>();
|
143
|
+
#view: View;
|
77
144
|
|
78
|
-
|
79
|
-
|
80
|
-
this
|
81
|
-
|
82
|
-
treeElement.select(/* omitFocus */ true, /* selectedByUser */ true);
|
83
|
-
}
|
84
|
-
// Expand until at least a certain number of matches is expanded.
|
85
|
-
if (this.matchesExpandedCount < matchesExpandedByDefault) {
|
86
|
-
treeElement.expand();
|
87
|
-
}
|
88
|
-
this.matchesExpandedCount += searchResult.matchesCount();
|
89
|
-
this.treeElements.push(treeElement);
|
145
|
+
constructor(searchConfig: Workspace.SearchConfig.SearchConfig, view: View = DEFAULT_VIEW) {
|
146
|
+
super({useShadowDom: true});
|
147
|
+
this.#view = view;
|
148
|
+
this.#searchConfig = searchConfig;
|
90
149
|
}
|
91
|
-
}
|
92
|
-
|
93
|
-
export const matchesExpandedByDefault = 200;
|
94
|
-
export const matchesShownAtOnce = 20;
|
95
150
|
|
96
|
-
|
97
|
-
|
98
|
-
private searchResult: SearchResult;
|
99
|
-
private initialized: boolean;
|
100
|
-
override toggleOnClick: boolean;
|
101
|
-
|
102
|
-
constructor(searchConfig: Workspace.SearchConfig.SearchConfig, searchResult: SearchResult) {
|
103
|
-
super('', true);
|
104
|
-
this.searchConfig = searchConfig;
|
105
|
-
this.searchResult = searchResult;
|
106
|
-
this.initialized = false;
|
107
|
-
this.toggleOnClick = true;
|
151
|
+
get searchResults(): SearchResult[] {
|
152
|
+
return this.#searchResults;
|
108
153
|
}
|
109
154
|
|
110
|
-
|
111
|
-
|
112
|
-
|
155
|
+
set searchResults(searchResults: SearchResult[]) {
|
156
|
+
this.#searchResults = searchResults;
|
157
|
+
let matchesExpandedCount = 0;
|
158
|
+
for (const searchResult of searchResults) {
|
159
|
+
if (this.#expandedResults.has(searchResult)) {
|
160
|
+
matchesExpandedCount += this.#searchMatches.get(searchResult)?.length ?? 0;
|
161
|
+
}
|
113
162
|
}
|
114
|
-
|
115
|
-
|
116
|
-
|
163
|
+
for (const searchResult of searchResults) {
|
164
|
+
if (matchesExpandedCount < matchesExpandedByDefault && !this.#expandedResults.has(searchResult)) {
|
165
|
+
this.#expandedResults.add(searchResult);
|
166
|
+
this.#onExpandSearchResult(searchResult);
|
167
|
+
matchesExpandedCount += this.#searchMatches.get(searchResult)?.length ?? 0;
|
168
|
+
}
|
169
|
+
}
|
170
|
+
this.requestUpdate();
|
117
171
|
}
|
118
172
|
|
119
173
|
showAllMatches(): void {
|
120
|
-
this
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
private updateMatchesUI(): void {
|
125
|
-
this.removeChildren();
|
126
|
-
const toIndex = Math.min(this.searchResult.matchesCount(), matchesShownAtOnce);
|
127
|
-
if (toIndex < this.searchResult.matchesCount()) {
|
128
|
-
this.appendSearchMatches(0, toIndex - 1);
|
129
|
-
this.appendShowMoreMatchesElement(toIndex - 1);
|
130
|
-
} else {
|
131
|
-
this.appendSearchMatches(0, toIndex);
|
174
|
+
for (const searchResult of this.#searchResults) {
|
175
|
+
const startMatchIndex = this.#searchMatches.get(searchResult)?.length ?? 0;
|
176
|
+
this.#appendSearchMatches(searchResult, startMatchIndex, searchResult.matchesCount());
|
132
177
|
}
|
178
|
+
this.requestUpdate();
|
133
179
|
}
|
134
180
|
|
135
|
-
|
136
|
-
this
|
181
|
+
collapseAllResults(): void {
|
182
|
+
this.#expandedResults = new WeakSet<SearchResult>();
|
183
|
+
this.requestUpdate();
|
137
184
|
}
|
138
185
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
<span class="search-result-file-name">${this.searchResult.label()}
|
144
|
-
<span class="search-result-dash">${'\u2014'}</span>
|
145
|
-
<span class="search-result-qualifier">${this.searchResult.description()}</span>
|
146
|
-
</span>
|
147
|
-
<span class="search-result-matches-count"
|
148
|
-
aria-label=${i18nString(UIStrings.matchesCountS, {PH1: this.searchResult.matchesCount()})}>
|
149
|
-
${this.searchResult.matchesCount()}
|
150
|
-
</span>`,
|
151
|
-
this.listItemElement);
|
152
|
-
// clang-format on
|
153
|
-
|
154
|
-
this.tooltip = this.searchResult.description();
|
155
|
-
if (this.expanded) {
|
156
|
-
this.updateMatchesUI();
|
157
|
-
}
|
186
|
+
#onExpandSearchResult(searchResult: SearchResult): void {
|
187
|
+
const toIndex = Math.min(searchResult.matchesCount(), matchesShownAtOnce);
|
188
|
+
this.#appendSearchMatches(searchResult, 0, toIndex);
|
189
|
+
this.requestUpdate();
|
158
190
|
}
|
159
191
|
|
160
|
-
|
161
|
-
const
|
162
|
-
|
163
|
-
const queries = this.searchConfig.queries();
|
192
|
+
#appendSearchMatches(searchResult: SearchResult, fromIndex: number, toIndex: number): void {
|
193
|
+
const queries = this.#searchConfig.queries();
|
164
194
|
const regexes = [];
|
165
195
|
for (let i = 0; i < queries.length; ++i) {
|
166
196
|
regexes.push(Platform.StringUtilities.createSearchRegex(
|
167
|
-
queries[i], !this
|
197
|
+
queries[i], !this.#searchConfig.ignoreCase(), this.#searchConfig.isRegex()));
|
198
|
+
}
|
199
|
+
|
200
|
+
const searchMatches = this.#searchMatches.get(searchResult) ?? [];
|
201
|
+
this.#searchMatches.set(searchResult, searchMatches);
|
202
|
+
if (searchMatches.length >= toIndex) {
|
203
|
+
return;
|
168
204
|
}
|
169
205
|
|
170
206
|
for (let i = fromIndex; i < toIndex; ++i) {
|
@@ -183,55 +219,32 @@ export class SearchResultsTreeElement extends UI.TreeOutline.TreeElement {
|
|
183
219
|
} else {
|
184
220
|
lineContent = lineContent.trim();
|
185
221
|
for (let j = 0; j < regexes.length; ++j) {
|
186
|
-
matchRanges = matchRanges.concat(this
|
222
|
+
matchRanges = matchRanges.concat(this.#regexMatchRanges(lineContent, regexes[j]));
|
187
223
|
}
|
188
224
|
({lineSegment: lineContent, matchRanges} = lineSegmentForMultipleMatches(lineContent, matchRanges));
|
189
225
|
}
|
190
226
|
|
191
227
|
const resultLabel = searchResult.matchLabel(i);
|
192
|
-
|
193
|
-
const searchMatchElement = new UI.TreeOutline.TreeElement();
|
194
|
-
this.appendChild(searchMatchElement);
|
195
|
-
// clang-format off
|
196
|
-
render(html`
|
197
|
-
<button class="devtools-link text-button link-style search-match-link"
|
198
|
-
jslog="Link; context: search-match; track: click" role="link" tabindex="0"
|
199
|
-
@click=${() => void Common.Revealer.reveal(searchResult.matchRevealable(i))}>
|
200
|
-
<span class="search-match-line-number"
|
201
|
-
aria-label=${typeof resultLabel === 'number' && !isNaN(resultLabel)
|
202
|
-
? i18nString(UIStrings.lineS, {PH1: resultLabel}) : resultLabel}>
|
203
|
-
${resultLabel}
|
204
|
-
</span>
|
205
|
-
<span class="search-match-content" aria-label="${lineContent} line">
|
206
|
-
${lineContent}
|
207
|
-
</span>
|
208
|
-
</button>`,
|
209
|
-
searchMatchElement.listItemElement);
|
210
|
-
// clang-format on
|
211
|
-
const contentSpan = searchMatchElement.listItemElement.querySelector('.search-match-content') as HTMLElement;
|
212
|
-
UI.UIUtils.highlightRangesWithStyleClass(contentSpan, matchRanges, 'highlighted-search-result');
|
213
|
-
searchMatchElement.listItemElement.className = 'search-match';
|
214
|
-
searchMatchElement.listItemElement.addEventListener('keydown', event => {
|
215
|
-
if (event.key === 'Enter') {
|
216
|
-
event.consume(true);
|
217
|
-
void Common.Revealer.reveal(searchResult.matchRevealable(i));
|
218
|
-
}
|
219
|
-
});
|
220
|
-
searchMatchElement.tooltip = lineContent;
|
228
|
+
searchMatches.push({lineContent, matchRanges, resultLabel});
|
221
229
|
}
|
222
230
|
}
|
223
231
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
+
override performUpdate(): void {
|
233
|
+
this.#view(
|
234
|
+
{
|
235
|
+
results: this.#searchResults,
|
236
|
+
matches: this.#searchMatches,
|
237
|
+
expandedResults: this.#expandedResults,
|
238
|
+
onSelectMatch: (searchResult, matchIndex) => {
|
239
|
+
void Common.Revealer.reveal(searchResult.matchRevealable(matchIndex));
|
240
|
+
},
|
241
|
+
onExpandSearchResult: this.#onExpandSearchResult.bind(this),
|
242
|
+
onShowMoreMatches: this.#onShowMoreMatches.bind(this),
|
243
|
+
},
|
244
|
+
{}, this.contentElement);
|
232
245
|
}
|
233
246
|
|
234
|
-
|
247
|
+
#regexMatchRanges(lineContent: string, regex: RegExp): TextUtils.TextRange.SourceRange[] {
|
235
248
|
regex.lastIndex = 0;
|
236
249
|
let match;
|
237
250
|
const matchRanges = [];
|
@@ -242,14 +255,16 @@ export class SearchResultsTreeElement extends UI.TreeOutline.TreeElement {
|
|
242
255
|
return matchRanges;
|
243
256
|
}
|
244
257
|
|
245
|
-
|
246
|
-
|
247
|
-
this.
|
248
|
-
this.
|
249
|
-
return false;
|
258
|
+
#onShowMoreMatches(searchResult: SearchResult): void {
|
259
|
+
const startMatchIndex = this.#searchMatches.get(searchResult)?.length ?? 0;
|
260
|
+
this.#appendSearchMatches(searchResult, startMatchIndex, searchResult.matchesCount());
|
261
|
+
this.requestUpdate();
|
250
262
|
}
|
251
263
|
}
|
252
264
|
|
265
|
+
export const matchesExpandedByDefault = 200;
|
266
|
+
export const matchesShownAtOnce = 20;
|
267
|
+
|
253
268
|
const DEFAULT_OPTS = {
|
254
269
|
prefixLength: 25,
|
255
270
|
maxLength: 1000,
|