chrome-devtools-frontend 1.0.1515988 → 1.0.1518653
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/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/front_end/core/common/README.md +13 -12
- package/front_end/core/host/GdpClient.ts +16 -1
- package/front_end/core/host/UserMetrics.ts +8 -2
- package/front_end/core/root/Runtime.ts +13 -0
- package/front_end/core/sdk/CSSMatchedStyles.ts +5 -1
- package/front_end/entrypoints/main/MainImpl.ts +6 -3
- package/front_end/generated/InspectorBackendCommands.js +10 -7
- package/front_end/generated/SupportedCSSProperties.js +21 -7
- 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/PerformanceAgent.ts +170 -54
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +14 -181
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +13 -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 +41 -19
- package/front_end/models/badges/Badge.ts +8 -3
- package/front_end/models/badges/CodeWhispererBadge.ts +2 -4
- package/front_end/models/badges/StarterBadge.ts +2 -2
- package/front_end/models/badges/UserBadges.ts +59 -6
- package/front_end/models/formatter/FormatterWorkerPool.ts +3 -3
- package/front_end/models/javascript_metadata/NativeFunctions.js +1 -1
- package/front_end/models/trace/README.md +28 -1
- package/front_end/models/trace/handlers/UserTimingsHandler.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 +16 -2
- package/front_end/panels/ai_assistance/components/ChatView.ts +9 -10
- package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +42 -0
- 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 +67 -15
- package/front_end/panels/common/GdpSignUpDialog.ts +18 -9
- package/front_end/panels/console/ConsolePrompt.ts +1 -1
- package/front_end/panels/console/ConsoleView.ts +6 -2
- package/front_end/panels/elements/ComputedStyleWidget.ts +1 -2
- 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/LayoutPane.ts +1 -1
- package/front_end/panels/elements/StylePropertyTreeElement.ts +21 -6
- package/front_end/panels/media/TickingFlameChart.ts +1 -1
- package/front_end/panels/network/NetworkLogView.ts +5 -1
- package/front_end/panels/profiler/HeapSnapshotView.ts +34 -19
- package/front_end/panels/search/SearchResultsPane.ts +126 -145
- package/front_end/panels/search/SearchView.ts +43 -59
- package/front_end/panels/settings/components/SyncSection.ts +16 -8
- package/front_end/panels/sources/AiCodeCompletionPlugin.ts +6 -1
- package/front_end/panels/sources/OutlineQuickOpen.ts +3 -1
- package/front_end/panels/sources/SourcesPanel.ts +3 -0
- 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 +18 -12
- 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/LiveMetricsView.ts +2 -2
- 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/cdp/Accessibility.js +0 -20
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Accessibility.js.map +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/revisions.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +1 -1
- 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/Mutex.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +2 -23
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Accessibility.js +0 -20
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Accessibility.js.map +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/revisions.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js.map +1 -1
- package/front_end/third_party/puppeteer/package/package.json +1 -1
- package/front_end/third_party/puppeteer/package/src/cdp/Accessibility.ts +1 -21
- package/front_end/third_party/puppeteer/package/src/generated/version.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/revisions.ts +1 -1
- package/front_end/ui/components/text_editor/config.ts +36 -8
- package/front_end/ui/components/tooltips/Tooltip.ts +71 -34
- 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 +16 -2
- 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/visual_logging/KnownContextValues.ts +24 -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> {
|
@@ -2,14 +2,15 @@
|
|
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
|
/* eslint-disable rulesdir/no-imperative-dom-api */
|
5
|
+
/* eslint-disable rulesdir/no-lit-render-outside-of-view */
|
5
6
|
|
6
7
|
import * as Common from '../../core/common/common.js';
|
7
8
|
import * as i18n from '../../core/i18n/i18n.js';
|
8
9
|
import * as Platform from '../../core/platform/platform.js';
|
9
10
|
import * as TextUtils from '../../models/text_utils/text_utils.js';
|
10
11
|
import type * as Workspace from '../../models/workspace/workspace.js';
|
11
|
-
import * as Components from '../../ui/legacy/components/utils/utils.js';
|
12
12
|
import * as UI from '../../ui/legacy/legacy.js';
|
13
|
+
import {html, render} from '../../ui/lit/lit.js';
|
13
14
|
|
14
15
|
import searchResultsPaneStyles from './searchResultsPane.css.js';
|
15
16
|
import type {SearchResult} from './SearchScope.js';
|
@@ -34,22 +35,95 @@ const UIStrings = {
|
|
34
35
|
const str_ = i18n.i18n.registerUIStrings('panels/search/SearchResultsPane.ts', UIStrings);
|
35
36
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
36
37
|
|
38
|
+
interface SearchMatch {
|
39
|
+
lineContent: string;
|
40
|
+
matchRanges: TextUtils.TextRange.SourceRange[];
|
41
|
+
resultLabel: string|number;
|
42
|
+
}
|
43
|
+
|
37
44
|
export class SearchResultsPane extends UI.Widget.VBox {
|
38
45
|
private readonly searchConfig: Workspace.SearchConfig.SearchConfig;
|
39
|
-
private readonly searchResults
|
40
|
-
private
|
46
|
+
private readonly searchResults = new Map<SearchResult, UI.TreeOutline.TreeElement>();
|
47
|
+
private expandedResults = new WeakSet<SearchResult>();
|
48
|
+
private readonly searchMatches = new WeakMap<SearchResult, SearchMatch[]>();
|
41
49
|
private treeOutline: UI.TreeOutline.TreeOutlineInShadow;
|
42
|
-
private matchesExpandedCount
|
50
|
+
private matchesExpandedCount = 0;
|
51
|
+
|
52
|
+
private addTreeElement(searchResult: SearchResult): void {
|
53
|
+
const treeElement = new UI.TreeOutline.TreeElement('', true);
|
54
|
+
treeElement.toggleOnClick = true;
|
55
|
+
this.searchResults.set(searchResult, treeElement);
|
56
|
+
this.treeOutline.appendChild(treeElement);
|
57
|
+
if (!this.treeOutline.selectedTreeElement) {
|
58
|
+
treeElement.select(/* omitFocus */ true, /* selectedByUser */ true);
|
59
|
+
}
|
60
|
+
treeElement.listItemElement.classList.add('search-result');
|
61
|
+
// clang-format off
|
62
|
+
render(html`
|
63
|
+
<span class="search-result-file-name">${searchResult.label()}
|
64
|
+
<span class="search-result-dash">${'\u2014'}</span>
|
65
|
+
<span class="search-result-qualifier">${searchResult.description()}</span>
|
66
|
+
</span>
|
67
|
+
<span class="search-result-matches-count"
|
68
|
+
aria-label=${i18nString(UIStrings.matchesCountS, {PH1: searchResult.matchesCount()})}>
|
69
|
+
${searchResult.matchesCount()}
|
70
|
+
</span>`,
|
71
|
+
treeElement.listItemElement);
|
72
|
+
// clang-format on
|
73
|
+
treeElement.tooltip = searchResult.description();
|
74
|
+
}
|
75
|
+
|
76
|
+
private appendSearchMatchElement(searchResult: SearchResult, match: SearchMatch, i: number): void {
|
77
|
+
const {lineContent, matchRanges, resultLabel} = match;
|
78
|
+
const element = this.searchResults.get(searchResult);
|
79
|
+
if (!element) {
|
80
|
+
return;
|
81
|
+
}
|
82
|
+
const searchMatchElement = new UI.TreeOutline.TreeElement();
|
83
|
+
element.appendChild(searchMatchElement);
|
84
|
+
// clang-format off
|
85
|
+
render(html`
|
86
|
+
<button class="devtools-link text-button link-style search-match-link"
|
87
|
+
jslog="Link; context: search-match; track: click" role="link" tabindex="0"
|
88
|
+
@click=${() => void Common.Revealer.reveal(searchResult.matchRevealable(i))}>
|
89
|
+
<span class="search-match-line-number"
|
90
|
+
aria-label=${typeof resultLabel === 'number' && !isNaN(resultLabel)
|
91
|
+
? i18nString(UIStrings.lineS, {PH1: resultLabel}) : resultLabel}>
|
92
|
+
${resultLabel}
|
93
|
+
</span>
|
94
|
+
<span class="search-match-content" aria-label="${lineContent} line">
|
95
|
+
${lineContent}
|
96
|
+
</span>
|
97
|
+
</button>`,
|
98
|
+
searchMatchElement.listItemElement);
|
99
|
+
// clang-format on
|
100
|
+
const contentSpan = searchMatchElement.listItemElement.querySelector('.search-match-content') as HTMLElement;
|
101
|
+
UI.UIUtils.highlightRangesWithStyleClass(contentSpan, matchRanges, 'highlighted-search-result');
|
102
|
+
searchMatchElement.listItemElement.className = 'search-match';
|
103
|
+
searchMatchElement.listItemElement.addEventListener('keydown', event => {
|
104
|
+
if (event.key === 'Enter') {
|
105
|
+
event.consume(true);
|
106
|
+
void Common.Revealer.reveal(searchResult.matchRevealable(i));
|
107
|
+
}
|
108
|
+
});
|
109
|
+
searchMatchElement.tooltip = lineContent;
|
110
|
+
}
|
43
111
|
|
44
112
|
constructor(searchConfig: Workspace.SearchConfig.SearchConfig) {
|
45
113
|
super({useShadowDom: true});
|
46
114
|
this.searchConfig = searchConfig;
|
47
|
-
|
48
|
-
this.searchResults = [];
|
49
|
-
this.treeElements = [];
|
50
115
|
this.treeOutline = new UI.TreeOutline.TreeOutlineInShadow();
|
51
116
|
this.treeOutline.registerRequiredCSS(searchResultsPaneStyles);
|
52
117
|
this.treeOutline.setHideOverflow(true);
|
118
|
+
this.treeOutline.addEventListener(
|
119
|
+
UI.TreeOutline.Events.ElementExpanded,
|
120
|
+
(event: Common.EventTarget.EventTargetEvent<UI.TreeOutline.TreeElement>) => {
|
121
|
+
const searchResult = this.searchResults.entries().find(entry => entry[1] === event.data)?.[0];
|
122
|
+
if (!searchResult) {
|
123
|
+
return;
|
124
|
+
}
|
125
|
+
this.expandSearchResult(searchResult);
|
126
|
+
});
|
53
127
|
|
54
128
|
this.contentElement.appendChild(this.treeOutline.element);
|
55
129
|
|
@@ -57,116 +131,43 @@ export class SearchResultsPane extends UI.Widget.VBox {
|
|
57
131
|
}
|
58
132
|
|
59
133
|
addSearchResult(searchResult: SearchResult): void {
|
60
|
-
this.searchResults.push(searchResult);
|
61
134
|
this.addTreeElement(searchResult);
|
62
|
-
}
|
63
|
-
|
64
|
-
showAllMatches(): void {
|
65
|
-
this.treeElements.forEach(treeElement => {
|
66
|
-
treeElement.expand();
|
67
|
-
treeElement.showAllMatches();
|
68
|
-
});
|
69
|
-
}
|
70
|
-
|
71
|
-
collapseAllResults(): void {
|
72
|
-
this.treeElements.forEach(treeElement => {
|
73
|
-
treeElement.collapse();
|
74
|
-
});
|
75
|
-
}
|
76
|
-
|
77
|
-
private addTreeElement(searchResult: SearchResult): void {
|
78
|
-
const treeElement = new SearchResultsTreeElement(this.searchConfig, searchResult);
|
79
|
-
this.treeOutline.appendChild(treeElement);
|
80
|
-
if (!this.treeOutline.selectedTreeElement) {
|
81
|
-
treeElement.select(/* omitFocus */ true, /* selectedByUser */ true);
|
82
|
-
}
|
83
135
|
// Expand until at least a certain number of matches is expanded.
|
84
136
|
if (this.matchesExpandedCount < matchesExpandedByDefault) {
|
85
|
-
|
137
|
+
this.searchResults.get(searchResult)?.expand();
|
86
138
|
}
|
87
|
-
this.matchesExpandedCount += searchResult.matchesCount();
|
88
|
-
this.treeElements.push(treeElement);
|
89
|
-
}
|
90
|
-
}
|
91
|
-
|
92
|
-
export const matchesExpandedByDefault = 200;
|
93
|
-
export const matchesShownAtOnce = 20;
|
94
|
-
|
95
|
-
export class SearchResultsTreeElement extends UI.TreeOutline.TreeElement {
|
96
|
-
private searchConfig: Workspace.SearchConfig.SearchConfig;
|
97
|
-
private searchResult: SearchResult;
|
98
|
-
private initialized: boolean;
|
99
|
-
override toggleOnClick: boolean;
|
100
|
-
|
101
|
-
constructor(searchConfig: Workspace.SearchConfig.SearchConfig, searchResult: SearchResult) {
|
102
|
-
super('', true);
|
103
|
-
this.searchConfig = searchConfig;
|
104
|
-
this.searchResult = searchResult;
|
105
|
-
this.initialized = false;
|
106
|
-
this.toggleOnClick = true;
|
107
139
|
}
|
108
140
|
|
109
|
-
|
110
|
-
|
111
|
-
|
141
|
+
showAllMatches(): void {
|
142
|
+
for (const searchResult of this.searchResults.keys()) {
|
143
|
+
const startMatchIndex = this.searchMatches.get(searchResult)?.length ?? 0;
|
144
|
+
this.appendSearchMatches(searchResult, startMatchIndex, searchResult.matchesCount());
|
112
145
|
}
|
113
|
-
|
114
|
-
this.updateMatchesUI();
|
115
|
-
this.initialized = true;
|
116
146
|
}
|
117
147
|
|
118
|
-
|
119
|
-
this.
|
120
|
-
|
148
|
+
collapseAllResults(): void {
|
149
|
+
for (const treeElement of this.searchResults.values()) {
|
150
|
+
treeElement.collapse();
|
151
|
+
}
|
121
152
|
}
|
122
153
|
|
123
|
-
private
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
this.
|
128
|
-
this.appendShowMoreMatchesElement(toIndex - 1);
|
154
|
+
private expandSearchResult(searchResult: SearchResult): void {
|
155
|
+
const toIndex = Math.min(searchResult.matchesCount(), matchesShownAtOnce);
|
156
|
+
if (toIndex < searchResult.matchesCount()) {
|
157
|
+
this.appendSearchMatches(searchResult, 0, toIndex - 1);
|
158
|
+
this.appendShowMoreMatchesElement(searchResult, toIndex - 1);
|
129
159
|
} else {
|
130
|
-
this.appendSearchMatches(0, toIndex);
|
160
|
+
this.appendSearchMatches(searchResult, 0, toIndex);
|
131
161
|
}
|
162
|
+
this.matchesExpandedCount += toIndex;
|
163
|
+
this.requestUpdate();
|
132
164
|
}
|
133
165
|
|
134
|
-
|
135
|
-
this.
|
166
|
+
private collapseSearchResult(searchResult: SearchResult): void {
|
167
|
+
this.searchResults.get(searchResult)?.collapse();
|
136
168
|
}
|
137
169
|
|
138
|
-
private
|
139
|
-
this.listItemElement.classList.add('search-result');
|
140
|
-
|
141
|
-
const fileNameSpan = span(this.searchResult.label(), 'search-result-file-name');
|
142
|
-
fileNameSpan.appendChild(span('\u2014', 'search-result-dash'));
|
143
|
-
fileNameSpan.appendChild(span(this.searchResult.description(), 'search-result-qualifier'));
|
144
|
-
|
145
|
-
this.tooltip = this.searchResult.description();
|
146
|
-
this.listItemElement.appendChild(fileNameSpan);
|
147
|
-
const matchesCountSpan = document.createElement('span');
|
148
|
-
matchesCountSpan.className = 'search-result-matches-count';
|
149
|
-
|
150
|
-
matchesCountSpan.textContent = `${this.searchResult.matchesCount()}`;
|
151
|
-
UI.ARIAUtils.setLabel(
|
152
|
-
matchesCountSpan, i18nString(UIStrings.matchesCountS, {PH1: this.searchResult.matchesCount()}));
|
153
|
-
|
154
|
-
this.listItemElement.appendChild(matchesCountSpan);
|
155
|
-
if (this.expanded) {
|
156
|
-
this.updateMatchesUI();
|
157
|
-
}
|
158
|
-
|
159
|
-
function span(text: string, className: string): Element {
|
160
|
-
const span = document.createElement('span');
|
161
|
-
span.className = className;
|
162
|
-
span.textContent = text;
|
163
|
-
return span;
|
164
|
-
}
|
165
|
-
}
|
166
|
-
|
167
|
-
private appendSearchMatches(fromIndex: number, toIndex: number): void {
|
168
|
-
const searchResult = this.searchResult;
|
169
|
-
|
170
|
+
private appendSearchMatches(searchResult: SearchResult, fromIndex: number, toIndex: number): void {
|
170
171
|
const queries = this.searchConfig.queries();
|
171
172
|
const regexes = [];
|
172
173
|
for (let i = 0; i < queries.length; ++i) {
|
@@ -174,6 +175,12 @@ export class SearchResultsTreeElement extends UI.TreeOutline.TreeElement {
|
|
174
175
|
queries[i], !this.searchConfig.ignoreCase(), this.searchConfig.isRegex()));
|
175
176
|
}
|
176
177
|
|
178
|
+
const searchMatches = this.searchMatches.get(searchResult) ?? [];
|
179
|
+
this.searchMatches.set(searchResult, searchMatches);
|
180
|
+
if (searchMatches.length > toIndex) {
|
181
|
+
return;
|
182
|
+
}
|
183
|
+
|
177
184
|
for (let i = fromIndex; i < toIndex; ++i) {
|
178
185
|
let lineContent = searchResult.matchLineContent(i);
|
179
186
|
let matchRanges: TextUtils.TextRange.SourceRange[] = [];
|
@@ -195,55 +202,24 @@ export class SearchResultsTreeElement extends UI.TreeOutline.TreeElement {
|
|
195
202
|
({lineSegment: lineContent, matchRanges} = lineSegmentForMultipleMatches(lineContent, matchRanges));
|
196
203
|
}
|
197
204
|
|
198
|
-
const anchor = Components.Linkifier.Linkifier.linkifyRevealable(
|
199
|
-
searchResult.matchRevealable(i), '', undefined, undefined, undefined, 'search-match');
|
200
|
-
anchor.classList.add('search-match-link');
|
201
|
-
anchor.tabIndex = 0;
|
202
|
-
const labelSpan = document.createElement('span');
|
203
|
-
labelSpan.classList.add('search-match-line-number');
|
204
205
|
const resultLabel = searchResult.matchLabel(i);
|
205
|
-
|
206
|
-
|
207
|
-
UI.ARIAUtils.setLabel(labelSpan, i18nString(UIStrings.lineS, {PH1: resultLabel}));
|
208
|
-
} else {
|
209
|
-
UI.ARIAUtils.setLabel(labelSpan, resultLabel);
|
210
|
-
}
|
211
|
-
anchor.appendChild(labelSpan);
|
212
|
-
|
213
|
-
const contentSpan = this.createContentSpan(lineContent, matchRanges);
|
214
|
-
anchor.appendChild(contentSpan);
|
215
|
-
|
216
|
-
const searchMatchElement = new UI.TreeOutline.TreeElement();
|
217
|
-
this.appendChild(searchMatchElement);
|
218
|
-
searchMatchElement.listItemElement.className = 'search-match';
|
219
|
-
searchMatchElement.listItemElement.appendChild(anchor);
|
220
|
-
searchMatchElement.listItemElement.addEventListener('keydown', event => {
|
221
|
-
if (event.key === 'Enter') {
|
222
|
-
event.consume(true);
|
223
|
-
void Common.Revealer.reveal(searchResult.matchRevealable(i));
|
224
|
-
}
|
225
|
-
});
|
226
|
-
searchMatchElement.tooltip = lineContent;
|
206
|
+
searchMatches.push({lineContent, matchRanges, resultLabel});
|
207
|
+
this.appendSearchMatchElement(searchResult, searchMatches[i], i);
|
227
208
|
}
|
228
209
|
}
|
229
210
|
|
230
|
-
private appendShowMoreMatchesElement(startMatchIndex: number): void {
|
231
|
-
const
|
211
|
+
private appendShowMoreMatchesElement(searchResult: SearchResult, startMatchIndex: number): void {
|
212
|
+
const element = this.searchResults.get(searchResult);
|
213
|
+
if (!element) {
|
214
|
+
return;
|
215
|
+
}
|
216
|
+
const matchesLeftCount = searchResult.matchesCount() - startMatchIndex;
|
232
217
|
const showMoreMatchesText = i18nString(UIStrings.showDMore, {PH1: matchesLeftCount});
|
233
218
|
const showMoreMatchesTreeElement = new UI.TreeOutline.TreeElement(showMoreMatchesText);
|
234
|
-
|
219
|
+
element.appendChild(showMoreMatchesTreeElement);
|
235
220
|
showMoreMatchesTreeElement.listItemElement.classList.add('show-more-matches');
|
236
221
|
showMoreMatchesTreeElement.onselect =
|
237
|
-
this.showMoreMatchesElementSelected.bind(this, showMoreMatchesTreeElement, startMatchIndex);
|
238
|
-
}
|
239
|
-
|
240
|
-
private createContentSpan(lineContent: string, matchRanges: TextUtils.TextRange.SourceRange[]): Element {
|
241
|
-
const contentSpan = document.createElement('span');
|
242
|
-
contentSpan.className = 'search-match-content';
|
243
|
-
contentSpan.textContent = lineContent;
|
244
|
-
UI.ARIAUtils.setLabel(contentSpan, `${lineContent} line`);
|
245
|
-
UI.UIUtils.highlightRangesWithStyleClass(contentSpan, matchRanges, 'highlighted-search-result');
|
246
|
-
return contentSpan;
|
222
|
+
this.showMoreMatchesElementSelected.bind(this, searchResult, showMoreMatchesTreeElement, startMatchIndex);
|
247
223
|
}
|
248
224
|
|
249
225
|
private regexMatchRanges(lineContent: string, regex: RegExp): TextUtils.TextRange.SourceRange[] {
|
@@ -258,13 +234,18 @@ export class SearchResultsTreeElement extends UI.TreeOutline.TreeElement {
|
|
258
234
|
}
|
259
235
|
|
260
236
|
private showMoreMatchesElementSelected(
|
261
|
-
showMoreMatchesTreeElement: UI.TreeOutline.TreeElement,
|
262
|
-
|
263
|
-
|
264
|
-
|
237
|
+
searchResult: SearchResult, showMoreMatchesTreeElement: UI.TreeOutline.TreeElement,
|
238
|
+
startMatchIndex: number): boolean {
|
239
|
+
const parentElement = showMoreMatchesTreeElement.parent;
|
240
|
+
parentElement?.removeChild(showMoreMatchesTreeElement);
|
241
|
+
this.appendSearchMatches(searchResult, startMatchIndex, searchResult.matchesCount());
|
242
|
+
return true;
|
265
243
|
}
|
266
244
|
}
|
267
245
|
|
246
|
+
export const matchesExpandedByDefault = 200;
|
247
|
+
export const matchesShownAtOnce = 20;
|
248
|
+
|
268
249
|
const DEFAULT_OPTS = {
|
269
250
|
prefixLength: 25,
|
270
251
|
maxLength: 1000,
|