chrome-devtools-frontend 1.0.1669021 → 1.0.1672388

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.
Files changed (208) hide show
  1. package/.agents/skills/fixing-skipped-tests/SKILL.md +6 -6
  2. package/.agents/skills/gerrit-cli/SKILL.md +4 -10
  3. package/.agents/skills/gerrit-cli/references/commands.md +45 -2
  4. package/.agents/skills/gerrit-cli/references/workflows.md +7 -0
  5. package/.agents/skills/gerrit-cli/scripts/import_upstream.py +34 -152
  6. package/config/typescript/tsconfig.eslint.json +1 -1
  7. package/docs/contributing/settings-experiments-features.md +2 -8
  8. package/docs/ecosystem/automatic_workspace_folders.md +0 -19
  9. package/eslint.config.mjs +2 -2
  10. package/front_end/core/common/Lazy.ts +3 -3
  11. package/front_end/core/common/SettingRegistration.ts +0 -7
  12. package/front_end/core/common/Settings.ts +0 -38
  13. package/front_end/core/host/UserMetrics.ts +187 -953
  14. package/front_end/core/host/UserMetricsEnums.d.ts +949 -0
  15. package/front_end/core/root/Runtime.ts +21 -133
  16. package/front_end/core/sdk/CSSMetadata.ts +70 -65
  17. package/front_end/core/sdk/CategorizedBreakpoint.ts +0 -1
  18. package/front_end/core/sdk/ChildTargetManager.ts +0 -2
  19. package/front_end/core/sdk/EmulationModel.ts +0 -2
  20. package/front_end/core/sdk/EventBreakpointsModel.ts +0 -4
  21. package/front_end/core/sdk/NetworkManager.ts +0 -3
  22. package/front_end/core/sdk/PageResourceLoader.ts +9 -9
  23. package/front_end/core/sdk/RehydratingConnection.ts +52 -4
  24. package/front_end/core/sdk/Target.ts +0 -4
  25. package/front_end/devtools_compatibility.js +886 -0
  26. package/front_end/entrypoints/inspector_main/RenderingOptions.ts +7 -6
  27. package/front_end/entrypoints/main/ExecutionContextSelector.ts +0 -1
  28. package/front_end/entrypoints/main/MainImpl.ts +18 -22
  29. package/front_end/foundation/Universe.ts +7 -2
  30. package/front_end/generated/InspectorBackendCommands.ts +3 -10
  31. package/front_end/generated/protocol-mapping.d.ts +0 -42
  32. package/front_end/generated/protocol-proxy-api.d.ts +0 -38
  33. package/front_end/generated/protocol.ts +9 -169
  34. package/front_end/models/ai_assistance/AiAgent2.ts +11 -3
  35. package/front_end/models/ai_assistance/AiConversation.ts +1 -0
  36. package/front_end/models/ai_assistance/AiHistoryStorage.ts +8 -5
  37. package/front_end/models/ai_assistance/AiSetting.ts +108 -0
  38. package/front_end/models/ai_assistance/AiUtils.ts +47 -0
  39. package/front_end/models/ai_assistance/ChangeManager.ts +1 -0
  40. package/front_end/models/ai_assistance/ExtensionScope.ts +3 -12
  41. package/front_end/models/ai_assistance/agents/AiAgent.ts +11 -18
  42. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +3 -0
  43. package/front_end/models/ai_assistance/agents/ExecuteJavascript.ts +42 -17
  44. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +3 -2
  45. package/front_end/models/ai_assistance/agents/StorageAgent.ts +253 -155
  46. package/front_end/models/ai_assistance/agents/StylingAgent.snapshot.txt +2 -2
  47. package/front_end/models/ai_assistance/ai_assistance.ts +4 -0
  48. package/front_end/models/ai_assistance/contexts/PerformanceTraceContext.ts +12 -6
  49. package/front_end/models/ai_assistance/data_formatters/FileFormatter.ts +3 -1
  50. package/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts +1 -0
  51. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +1 -0
  52. package/front_end/models/ai_assistance/injected.ts +1 -0
  53. package/front_end/models/ai_assistance/performance/AICallTree.ts +1 -0
  54. package/front_end/models/ai_assistance/skills/Skill.ts +1 -1
  55. package/front_end/models/ai_assistance/skills/SkillRegistry.ts +2 -0
  56. package/front_end/models/ai_assistance/skills/performance.md +10 -0
  57. package/front_end/models/ai_assistance/tools/ExecuteJavaScript.ts +52 -5
  58. package/front_end/models/ai_assistance/tools/GetElementAccessibilityDetails.ts +4 -4
  59. package/front_end/models/ai_assistance/tools/GetLighthouseAudits.ts +4 -4
  60. package/front_end/models/ai_assistance/tools/GetNetworkRequestDetails.ts +5 -4
  61. package/front_end/models/ai_assistance/tools/GetStyles.ts +5 -4
  62. package/front_end/models/ai_assistance/tools/ListNetworkRequests.ts +5 -4
  63. package/front_end/models/ai_assistance/tools/README.md +1 -1
  64. package/front_end/models/ai_assistance/tools/RecordPerformanceTrace.ts +63 -0
  65. package/front_end/models/ai_assistance/tools/ResolveDevtoolsNodePath.ts +5 -5
  66. package/front_end/models/ai_assistance/tools/Tool.ts +118 -24
  67. package/front_end/models/ai_assistance/tools/ToolRegistry.ts +2 -0
  68. package/front_end/models/badges/UserBadges.ts +2 -0
  69. package/front_end/models/bindings/NetworkProject.ts +5 -0
  70. package/front_end/models/bindings/ResourceScriptMapping.ts +2 -0
  71. package/front_end/models/bindings/ResourceUtils.ts +3 -0
  72. package/front_end/models/crux-manager/CrUXManager.ts +1 -0
  73. package/front_end/models/emulation/DeviceModeModel.ts +140 -7
  74. package/front_end/models/emulation/EmulatedDevices.ts +246 -793
  75. package/front_end/models/issues_manager/IssuesManager.ts +10 -2
  76. package/front_end/models/live-metrics/LiveMetrics.ts +41 -9
  77. package/front_end/models/logs/LogManager.ts +8 -5
  78. package/front_end/models/logs/NetworkLog.ts +1 -0
  79. package/front_end/models/persistence/IsolatedFileSystemManager.ts +21 -3
  80. package/front_end/models/persistence/NetworkPersistenceManager.ts +6 -0
  81. package/front_end/models/project_settings/ProjectSettingsModel.ts +8 -12
  82. package/front_end/models/trace_source_maps_resolver/SourceMapsResolver.ts +3 -1
  83. package/front_end/models/workspace/IgnoreListManager.ts +2 -0
  84. package/front_end/models/workspace/UISourceCode.ts +2 -0
  85. package/front_end/models/workspace_diff/WorkspaceDiff.ts +4 -0
  86. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +22 -22
  87. package/front_end/panels/ai_assistance/ai_assistance-meta.ts +0 -7
  88. package/front_end/panels/ai_assistance/components/ChatInput.ts +4 -0
  89. package/front_end/panels/ai_assistance/components/ChatMessage.ts +79 -34
  90. package/front_end/panels/ai_assistance/components/WalkthroughView.ts +1 -2
  91. package/front_end/panels/ai_assistance/components/walkthroughView.css +1 -1
  92. package/front_end/panels/application/ApplicationPanelSidebar.ts +9 -106
  93. package/front_end/panels/application/ApplicationPanelTreeElement.ts +1 -1
  94. package/front_end/panels/application/application.ts +0 -10
  95. package/front_end/panels/application/components/components.ts +0 -4
  96. package/front_end/panels/browser_debugger/CategorizedBreakpointsSidebarPane.ts +0 -5
  97. package/front_end/panels/browser_debugger/EventListenerBreakpointsSidebarPane.ts +6 -12
  98. package/front_end/panels/browser_debugger/browser_debugger-meta.ts +5 -3
  99. package/front_end/panels/console/ConsoleFormat.ts +2 -62
  100. package/front_end/panels/console/ConsoleViewMessage.ts +14 -7
  101. package/front_end/panels/emulation/AdvancedApp.ts +1 -2
  102. package/front_end/panels/emulation/DeviceModeToolbar.ts +83 -69
  103. package/front_end/panels/emulation/DeviceModeView.ts +4 -134
  104. package/front_end/panels/emulation/DeviceModeWrapper.ts +52 -69
  105. package/front_end/panels/emulation/MediaQueryInspector.ts +2 -2
  106. package/front_end/panels/emulation/emulation-meta.ts +12 -12
  107. package/front_end/panels/issues/IssuesPane.ts +3 -1
  108. package/front_end/panels/lighthouse/LighthouseController.ts +6 -0
  109. package/front_end/panels/linear_memory_inspector/components/LinearMemoryInspector.ts +17 -21
  110. package/front_end/panels/linear_memory_inspector/components/LinearMemoryNavigator.ts +206 -126
  111. package/front_end/panels/linear_memory_inspector/components/linearMemoryInspector.css +1 -1
  112. package/front_end/panels/mobile_throttling/CalibrationController.ts +1 -1
  113. package/front_end/panels/mobile_throttling/MobileThrottlingSelector.ts +3 -3
  114. package/front_end/panels/mobile_throttling/NetworkPanelIndicator.ts +6 -6
  115. package/front_end/panels/mobile_throttling/NetworkThrottlingSelector.ts +11 -11
  116. package/front_end/panels/mobile_throttling/ThrottlingManager.ts +13 -13
  117. package/front_end/panels/mobile_throttling/ThrottlingPresets.ts +10 -10
  118. package/front_end/panels/mobile_throttling/ThrottlingSettingsTab.ts +28 -28
  119. package/front_end/panels/mobile_throttling/mobile_throttling-meta.ts +6 -6
  120. package/front_end/panels/network/RequestHeadersView.ts +1 -1
  121. package/front_end/panels/network/ResourceChunkView.ts +243 -144
  122. package/front_end/panels/network/ResourceDirectSocketChunkView.ts +52 -29
  123. package/front_end/panels/network/ResourceWebSocketFrameView.ts +21 -35
  124. package/front_end/panels/network/resourceChunkView.css +41 -36
  125. package/front_end/panels/profiler/HeapDetachedElementsDataGrid.ts +21 -12
  126. package/front_end/panels/profiler/profiler.ts +4 -0
  127. package/front_end/panels/recorder/RecorderPanel.ts +6 -14
  128. package/front_end/panels/sensors/LocationsSettingsTab.ts +7 -7
  129. package/front_end/panels/settings/AISettingsTab.ts +75 -31
  130. package/front_end/panels/settings/SettingsScreen.ts +8 -13
  131. package/front_end/panels/settings/components/SyncSection.ts +3 -4
  132. package/front_end/panels/settings/emulation/DevicesSettingsTab.ts +200 -18
  133. package/front_end/panels/settings/emulation/devicesSettingsTab.css +18 -0
  134. package/front_end/panels/settings/settings-meta.ts +0 -1
  135. package/front_end/panels/sources/CategorizedBreakpointL10n.ts +0 -2
  136. package/front_end/panels/sources/DebuggerPausedMessage.ts +11 -5
  137. package/front_end/panels/sources/DebuggerPlugin.ts +1 -1
  138. package/front_end/panels/sources/EditingLocationHistoryManager.ts +12 -9
  139. package/front_end/panels/sources/SourcesPanel.ts +19 -17
  140. package/front_end/panels/sources/SourcesView.ts +191 -96
  141. package/front_end/panels/sources/TabbedEditorContainer.ts +3 -4
  142. package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +2 -5
  143. package/front_end/panels/timeline/TimelineUIUtils.ts +15 -0
  144. package/front_end/panels/timeline/timeline-meta.ts +3 -5
  145. package/front_end/third_party/chromium/README.chromium +1 -1
  146. package/front_end/third_party/codemirror.next/chunk/angular.js +1 -1
  147. package/front_end/third_party/codemirror.next/chunk/codemirror.js +1 -1
  148. package/front_end/third_party/codemirror.next/chunk/codemirror.js.map +1 -1
  149. package/front_end/third_party/codemirror.next/chunk/cpp.js +1 -1
  150. package/front_end/third_party/codemirror.next/chunk/cpp.js.map +1 -1
  151. package/front_end/third_party/codemirror.next/chunk/java.js +1 -1
  152. package/front_end/third_party/codemirror.next/chunk/java.js.map +1 -1
  153. package/front_end/third_party/codemirror.next/chunk/legacy.js +1 -1
  154. package/front_end/third_party/codemirror.next/chunk/less.js +1 -1
  155. package/front_end/third_party/codemirror.next/chunk/less.js.map +1 -1
  156. package/front_end/third_party/codemirror.next/chunk/markdown.js +1 -1
  157. package/front_end/third_party/codemirror.next/chunk/markdown.js.map +1 -1
  158. package/front_end/third_party/codemirror.next/chunk/php.js +1 -1
  159. package/front_end/third_party/codemirror.next/chunk/php.js.map +1 -1
  160. package/front_end/third_party/codemirror.next/chunk/python.js +1 -1
  161. package/front_end/third_party/codemirror.next/chunk/python.js.map +1 -1
  162. package/front_end/third_party/codemirror.next/chunk/sass.js +1 -1
  163. package/front_end/third_party/codemirror.next/chunk/sass.js.map +1 -1
  164. package/front_end/third_party/codemirror.next/chunk/svelte.js +1 -1
  165. package/front_end/third_party/codemirror.next/chunk/svelte.js.map +1 -1
  166. package/front_end/third_party/codemirror.next/chunk/vue.js +1 -1
  167. package/front_end/third_party/codemirror.next/chunk/wast.js +1 -1
  168. package/front_end/third_party/codemirror.next/chunk/wast.js.map +1 -1
  169. package/front_end/third_party/codemirror.next/chunk/xml.js +1 -1
  170. package/front_end/third_party/codemirror.next/chunk/xml.js.map +1 -1
  171. package/front_end/third_party/codemirror.next/codemirror.next.d.ts +1332 -193
  172. package/front_end/third_party/codemirror.next/codemirror.next.js +1 -1
  173. package/front_end/third_party/codemirror.next/rebuild.sh +1 -1
  174. package/front_end/tsconfig.compatibility.json +2 -1
  175. package/front_end/tsconfig.json +1 -1
  176. package/front_end/ui/components/icon_button/IconButton.ts +1 -1
  177. package/front_end/ui/components/issue_counter/IssueCounter.ts +1 -1
  178. package/front_end/ui/components/settings/SettingCheckbox.ts +4 -7
  179. package/front_end/ui/components/settings/settings.ts +1 -2
  180. package/front_end/ui/legacy/Treeoutline.ts +52 -30
  181. package/front_end/ui/legacy/components/object_ui/CSSStyleSanitizer.ts +74 -0
  182. package/front_end/ui/legacy/components/object_ui/CustomPreviewComponent.ts +6 -1
  183. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +47 -54
  184. package/front_end/ui/legacy/components/object_ui/object_ui.ts +2 -0
  185. package/front_end/ui/legacy/components/quick_open/CommandMenu.ts +5 -27
  186. package/front_end/ui/legacy/components/settings_ui/SettingsUI.ts +10 -12
  187. package/front_end/ui/settings/SettingUIRegistration.ts +0 -8
  188. package/front_end/ui/visual_logging/KnownContextValues.ts +21 -0
  189. package/inspector_overlay/tsconfig.json +8 -2
  190. package/package.json +3 -2
  191. package/.agents/skills/gerrit-cli/scripts/gerrit_client_wrapper.py +0 -47
  192. package/front_end/core/sdk/CSSModel.test.api.ts +0 -102
  193. package/front_end/core/sdk/DOMModel.test.api.ts +0 -104
  194. package/front_end/foundation/Universe.test.api.ts +0 -73
  195. package/front_end/panels/application/SharedStorageEventsView.ts +0 -128
  196. package/front_end/panels/application/SharedStorageItemsView.ts +0 -179
  197. package/front_end/panels/application/SharedStorageListTreeElement.ts +0 -65
  198. package/front_end/panels/application/SharedStorageModel.ts +0 -249
  199. package/front_end/panels/application/SharedStorageTreeElement.ts +0 -40
  200. package/front_end/panels/application/components/SharedStorageAccessGrid.ts +0 -191
  201. package/front_end/panels/application/components/SharedStorageMetadataView.ts +0 -133
  202. package/front_end/panels/application/components/sharedStorageAccessGrid.css +0 -29
  203. package/front_end/panels/application/components/sharedStorageMetadataView.css +0 -29
  204. package/front_end/panels/application/sharedStorageEventsView.css +0 -9
  205. package/front_end/panels/network/OriginalResourceChunkView.ts +0 -340
  206. package/front_end/panels/network/originalResourceChunkView.css +0 -49
  207. package/front_end/ui/components/settings/SettingDeprecationWarning.ts +0 -47
  208. package/front_end/ui/components/settings/settingDeprecationWarning.css +0 -14
@@ -384,7 +384,7 @@ export class GenericSettingsTab extends UI.Widget.VBox implements SettingsTab {
384
384
 
385
385
  export class ExperimentsSettingsTab extends UI.Widget.VBox implements SettingsTab {
386
386
  #experimentsSection: Card|undefined;
387
- private readonly experimentToControl = new Map<Root.Runtime.Experiment|Root.Runtime.HostExperiment, HTMLElement>();
387
+ private readonly experimentToControl = new Map<Root.Runtime.Experiment, HTMLElement>();
388
388
  private readonly containerElement: HTMLElement;
389
389
 
390
390
  constructor() {
@@ -452,19 +452,16 @@ export class ExperimentsSettingsTab extends UI.Widget.VBox implements SettingsTa
452
452
  return subsection;
453
453
  }
454
454
 
455
- private createExperimentCheckbox(experiment: Root.Runtime.Experiment|
456
- Root.Runtime.HostExperiment): HTMLParagraphElement {
455
+ private createExperimentCheckbox(experiment: Root.Runtime.Experiment): HTMLParagraphElement {
457
456
  const checkbox =
458
457
  UI.UIUtils.CheckboxLabel.createWithStringLiteral(experiment.title, experiment.isEnabled(), experiment.name);
459
458
  checkbox.classList.add('experiment-label');
460
459
  checkbox.name = experiment.name;
461
460
  function listener(): void {
462
- if (experiment instanceof Root.Runtime.HostExperiment) {
463
- Host.InspectorFrontendHost.InspectorFrontendHostInstance.setChromeFlag(experiment.aboutFlag, checkbox.checked);
464
- }
461
+ Host.InspectorFrontendHost.InspectorFrontendHostInstance.setChromeFlag(experiment.aboutFlag, checkbox.checked);
465
462
  experiment.setEnabled(checkbox.checked);
466
463
  Host.userMetrics.experimentChanged(experiment.name, experiment.isEnabled());
467
- if (experiment instanceof Root.Runtime.HostExperiment && experiment.requiresChromeRestart) {
464
+ if (experiment.requiresChromeRestart) {
468
465
  UI.InspectorView.InspectorView.instance().displayChromeRestartRequiredWarning(
469
466
  i18nString(UIStrings.settingsChangedRestartChrome));
470
467
  } else {
@@ -507,7 +504,7 @@ export class ExperimentsSettingsTab extends UI.Widget.VBox implements SettingsTa
507
504
  }
508
505
 
509
506
  highlightObject(experiment: Object): void {
510
- if (experiment instanceof Root.Runtime.Experiment || experiment instanceof Root.Runtime.HostExperiment) {
507
+ if (experiment instanceof Root.Runtime.Experiment) {
511
508
  const element = this.experimentToControl.get(experiment);
512
509
  if (element) {
513
510
  PanelUtils.highlightElement(element);
@@ -542,12 +539,10 @@ export class ActionDelegate implements UI.ActionRegistration.ActionDelegate {
542
539
  return false;
543
540
  }
544
541
  }
545
- export class Revealer implements
546
- Common.Revealer.Revealer<Root.Runtime.Experiment|Root.Runtime.HostExperiment|Common.Settings.Setting<unknown>> {
547
- async reveal(object: Root.Runtime.Experiment|Root.Runtime.HostExperiment|
548
- Common.Settings.Setting<unknown>): Promise<void> {
542
+ export class Revealer implements Common.Revealer.Revealer<Root.Runtime.Experiment|Common.Settings.Setting<unknown>> {
543
+ async reveal(object: Root.Runtime.Experiment|Common.Settings.Setting<unknown>): Promise<void> {
549
544
  const context = UI.Context.Context.instance();
550
- if (object instanceof Root.Runtime.Experiment || object instanceof Root.Runtime.HostExperiment) {
545
+ if (object instanceof Root.Runtime.Experiment) {
551
546
  Host.InspectorFrontendHost.InspectorFrontendHostInstance.bringToFront();
552
547
  await SettingsScreen.showSettingsScreen({name: 'experiments'});
553
548
  const experimentsSettingsTab = context.flavor(ExperimentsSettingsTab);
@@ -121,7 +121,7 @@ const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLElement)
121
121
  return html`
122
122
  <div class="setting-checkbox-container">
123
123
  <setting-checkbox class="setting-checkbox"
124
- .data=${{ setting: input.syncSetting } as SettingsComponents.SettingCheckbox.SettingCheckboxData}>
124
+ .data=${{ setting: input.syncSetting, disabled: input.checkboxDisabled } as SettingsComponents.SettingCheckbox.SettingCheckboxData}>
125
125
  </setting-checkbox>
126
126
  ${input.warningType ? html`
127
127
  <devtools-button
@@ -251,6 +251,7 @@ export interface SyncSectionData {
251
251
  export interface ViewInput {
252
252
  syncInfo: Host.InspectorFrontendHostAPI.SyncInformation;
253
253
  syncSetting: Common.Settings.Setting<boolean>;
254
+ checkboxDisabled: boolean;
254
255
  receiveBadgesSetting?: Common.Settings.Setting<boolean>;
255
256
  isEligibleToCreateGdpProfile: boolean;
256
257
  gdpProfile?: Host.GdpClient.Profile;
@@ -302,10 +303,7 @@ export class SyncSection extends UI.Widget.Widget {
302
303
  }
303
304
 
304
305
  override performUpdate(): void {
305
- // TODO: this should not probably happen in render, instead, the setting
306
- // should be disabled.
307
306
  const checkboxDisabled = !this.#syncInfo.isSyncActive || !this.#syncInfo.arePreferencesSynced;
308
- this.#syncSetting?.setDisabled(checkboxDisabled);
309
307
 
310
308
  let warningType: WarningType|undefined;
311
309
  if (!this.#syncInfo.isSyncActive) {
@@ -317,6 +315,7 @@ export class SyncSection extends UI.Widget.Widget {
317
315
  const viewInput: ViewInput = {
318
316
  syncInfo: this.#syncInfo,
319
317
  syncSetting: this.#syncSetting,
318
+ checkboxDisabled,
320
319
  receiveBadgesSetting: this.#receiveBadgesSetting,
321
320
  gdpProfile: this.#gdpProfile,
322
321
  isEligibleToCreateGdpProfile: Host.GdpClient.isGdpProfilesAvailable() && this.#isEligibleToCreateGdpProfile,
@@ -74,17 +74,67 @@ const UIStrings = {
74
74
  * @description Error message in the Devices settings tab shown when the user agent string is empty.
75
75
  */
76
76
  userAgentStringCannotBeEmpty: 'User agent string can’t be empty.',
77
+ /**
78
+ * @description Label for portrait safe-area values on a custom device.
79
+ */
80
+ portraitSafeArea: 'Portrait safe area',
81
+ /**
82
+ * @description Label for landscape safe-area values on a custom device.
83
+ */
84
+ landscapeSafeArea: 'Landscape safe area',
85
+ /**
86
+ * @description Placeholder text for a custom device safe-area left inset field.
87
+ */
88
+ safeAreaLeft: 'Left inset',
89
+ /**
90
+ * @description Placeholder text for a custom device safe-area top inset field.
91
+ */
92
+ safeAreaTop: 'Top inset',
93
+ /**
94
+ * @description Placeholder text for a custom device safe-area right inset field.
95
+ */
96
+ safeAreaRight: 'Right inset',
97
+ /**
98
+ * @description Placeholder text for a custom device safe-area bottom inset field.
99
+ */
100
+ safeAreaBottom: 'Bottom inset',
101
+ /**
102
+ * @description Error message shown when a custom device safe-area value is invalid.
103
+ * @example {Portrait safe area} PH1
104
+ * @example {Top inset} PH2
105
+ * @example {9999} PH3
106
+ */
107
+ safeAreaValueMustBeInRange: '{PH1}: {PH2} must be an integer from 0 to {PH3}.',
77
108
  } as const;
78
109
  const str_ = i18n.i18n.registerUIStrings('panels/settings/emulation/DevicesSettingsTab.ts', UIStrings);
79
110
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
80
111
 
112
+ function parseOptionalNonNegativeInteger(value: string): number|null {
113
+ const trimmedValue = value.trim();
114
+ if (!trimmedValue) {
115
+ return 0;
116
+ }
117
+ if (!/^\d+$/.test(trimmedValue)) {
118
+ return null;
119
+ }
120
+ const parsedValue = Number(trimmedValue);
121
+ if (!Number.isSafeInteger(parsedValue) || parsedValue < 0 ||
122
+ parsedValue > EmulationModel.DeviceModeModel.MaxDeviceSize) {
123
+ return null;
124
+ }
125
+ return parsedValue;
126
+ }
127
+
81
128
  export class DevicesSettingsTab extends UI.Widget.VBox implements
82
129
  UI.ListWidget.Delegate<EmulationModel.EmulatedDevices.EmulatedDevice> {
83
130
  containerElement: HTMLElement;
84
131
  private readonly addCustomButton: Buttons.Button.Button;
85
132
  private readonly ariaSuccessMessageElement: HTMLElement;
86
133
  readonly #customDeviceList: UI.ListWidget.ListWidget<EmulationModel.EmulatedDevices.EmulatedDevice>;
87
- readonly #defaultDeviceList: UI.ListWidget.ListWidget<EmulationModel.EmulatedDevices.EmulatedDevice>;
134
+ readonly #defaultDeviceLists = new Map<EmulationModel.EmulatedDevices.Category, {
135
+ container: HTMLElement,
136
+ list: UI.ListWidget.ListWidget<EmulationModel.EmulatedDevices.EmulatedDevice>,
137
+ }>();
88
138
  private muteUpdate: boolean;
89
139
  private emulatedDevicesList: EmulationModel.EmulatedDevices.EmulatedDevicesList;
90
140
  private editor?: UI.ListWidget.Editor<EmulationModel.EmulatedDevices.EmulatedDevice>;
@@ -97,10 +147,6 @@ export class DevicesSettingsTab extends UI.Widget.VBox implements
97
147
  this.contentElement.createChild('div', 'settings-card-container-wrapper').createChild('div');
98
148
  this.containerElement.classList.add('settings-card-container', 'ignore-list-settings');
99
149
 
100
- this.#defaultDeviceList = new UI.ListWidget.ListWidget(this, false /* delegatesFocus */);
101
- this.#defaultDeviceList.registerRequiredCSS(devicesSettingsTabStyles);
102
- this.#defaultDeviceList.element.classList.add('devices-list', 'device-card-content');
103
-
104
150
  this.muteUpdate = false;
105
151
  this.emulatedDevicesList = EmulationModel.EmulatedDevices.EmulatedDevicesList.instance();
106
152
  this.emulatedDevicesList.addEventListener(
@@ -132,7 +178,23 @@ export class DevicesSettingsTab extends UI.Widget.VBox implements
132
178
 
133
179
  const defaultDevicesCard = this.containerElement.createChild('devtools-card');
134
180
  defaultDevicesCard.heading = i18nString(UIStrings.defaultDevices);
135
- defaultDevicesCard.append(this.#defaultDeviceList.element);
181
+
182
+ for (const category of EmulationModel.EmulatedDevices.CATEGORY_ORDER) {
183
+ const groupContainer = document.createElement('div');
184
+ groupContainer.classList.add('device-group-container');
185
+
186
+ const groupTitle = groupContainer.createChild('div', 'device-group-title');
187
+ groupTitle.textContent = EmulationModel.EmulatedDevices.getCategoryTitle(category);
188
+
189
+ defaultDevicesCard.append(groupContainer);
190
+
191
+ const listWidget = new UI.ListWidget.ListWidget(this, false /* delegatesFocus */);
192
+ listWidget.registerRequiredCSS(devicesSettingsTabStyles);
193
+ listWidget.element.classList.add('devices-list', 'device-card-content');
194
+ listWidget.show(groupContainer);
195
+
196
+ this.#defaultDeviceLists.set(category, {container: groupContainer, list: listWidget});
197
+ }
136
198
  }
137
199
 
138
200
  override wasShown(): void {
@@ -145,18 +207,32 @@ export class DevicesSettingsTab extends UI.Widget.VBox implements
145
207
  return;
146
208
  }
147
209
 
148
- this.#defaultDeviceList.clear();
210
+ for (const {list} of this.#defaultDeviceLists.values()) {
211
+ list.clear();
212
+ }
149
213
  this.#customDeviceList.clear();
150
214
 
151
- let devices = this.emulatedDevicesList.custom().slice();
152
- for (let i = 0; i < devices.length; ++i) {
153
- this.#customDeviceList.appendItem(devices[i], true);
215
+ const customDevices = this.emulatedDevicesList.custom().slice();
216
+ for (let i = 0; i < customDevices.length; ++i) {
217
+ this.#customDeviceList.appendItem(customDevices[i], true);
154
218
  }
155
219
 
156
- devices = this.emulatedDevicesList.standard().slice();
157
- devices.sort(EmulationModel.EmulatedDevices.EmulatedDevice.deviceComparator);
158
- for (let i = 0; i < devices.length; ++i) {
159
- this.#defaultDeviceList.appendItem(devices[i], false);
220
+ const standardDevices = this.emulatedDevicesList.standard().slice();
221
+ standardDevices.sort(EmulationModel.EmulatedDevices.EmulatedDevice.deviceComparator);
222
+
223
+ const categoryItemCounts = new Map<EmulationModel.EmulatedDevices.Category, number>();
224
+ for (const device of standardDevices) {
225
+ const cat = EmulationModel.EmulatedDevices.deviceCategory(device);
226
+ const group = this.#defaultDeviceLists.get(cat);
227
+ if (group) {
228
+ group.list.appendItem(device, false);
229
+ categoryItemCounts.set(cat, (categoryItemCounts.get(cat) || 0) + 1);
230
+ }
231
+ }
232
+
233
+ for (const [cat, group] of this.#defaultDeviceLists.entries()) {
234
+ const count = categoryItemCounts.get(cat) || 0;
235
+ group.container.style.display = count > 0 ? '' : 'none';
160
236
  }
161
237
  }
162
238
 
@@ -185,6 +261,21 @@ export class DevicesSettingsTab extends UI.Widget.VBox implements
185
261
  return value ? String(value) : '';
186
262
  }
187
263
 
264
+ private verticalMode(device: EmulationModel.EmulatedDevices.EmulatedDevice): EmulationModel.EmulatedDevices.Mode
265
+ |null {
266
+ return device.modes.find(mode => mode.orientation === EmulationModel.EmulatedDevices.Vertical) || null;
267
+ }
268
+
269
+ private horizontalMode(device: EmulationModel.EmulatedDevices.EmulatedDevice): EmulationModel.EmulatedDevices.Mode
270
+ |null {
271
+ return device.modes.find(mode => mode.orientation === EmulationModel.EmulatedDevices.Horizontal) || null;
272
+ }
273
+
274
+ private editorIntegerValue(editor: UI.ListWidget.Editor<EmulationModel.EmulatedDevices.EmulatedDevice>,
275
+ controlName: string): number {
276
+ return parseOptionalNonNegativeInteger(editor.control(controlName).value) ?? 0;
277
+ }
278
+
188
279
  renderItem(device: EmulationModel.EmulatedDevices.EmulatedDevice, editable: boolean): Element {
189
280
  const label = document.createElement('label');
190
281
  label.classList.add('devices-list-item');
@@ -222,18 +313,28 @@ export class DevicesSettingsTab extends UI.Widget.VBox implements
222
313
  device.deviceScaleFactor = editor.control('scale').value ? parseFloat(editor.control('scale').value) : 0;
223
314
  device.userAgent = editor.control('user-agent').value;
224
315
  device.modes = [];
225
- device.modes.push({
316
+ const verticalMode: EmulationModel.EmulatedDevices.Mode = {
226
317
  title: '',
227
318
  orientation: EmulationModel.EmulatedDevices.Vertical,
228
319
  insets: new EmulationModel.DeviceModeModel.Insets(0, 0, 0, 0),
229
320
  image: null,
230
- });
231
- device.modes.push({
321
+ };
322
+ const safeAreaInsets = this.safeAreaInsetsFromEditor(editor);
323
+ if (safeAreaInsets) {
324
+ verticalMode.safeAreaInsets = safeAreaInsets;
325
+ }
326
+ device.modes.push(verticalMode);
327
+ const horizontalMode: EmulationModel.EmulatedDevices.Mode = {
232
328
  title: '',
233
329
  orientation: EmulationModel.EmulatedDevices.Horizontal,
234
330
  insets: new EmulationModel.DeviceModeModel.Insets(0, 0, 0, 0),
235
331
  image: null,
236
- });
332
+ };
333
+ const landscapeSafeAreaInsets = this.safeAreaInsetsFromEditor(editor, 'landscape-');
334
+ if (landscapeSafeAreaInsets) {
335
+ horizontalMode.safeAreaInsets = landscapeSafeAreaInsets;
336
+ }
337
+ device.modes.push(horizontalMode);
237
338
  device.capabilities = [];
238
339
  const uaType = editor.control('ua-type').value;
239
340
  if (uaType === EmulationModel.DeviceModeModel.UA.MOBILE ||
@@ -277,6 +378,7 @@ export class DevicesSettingsTab extends UI.Widget.VBox implements
277
378
  editor.control('height').value = this.toNumericInputValue(device.vertical.height);
278
379
  editor.control('scale').value = this.toNumericInputValue(device.deviceScaleFactor);
279
380
  editor.control('user-agent').value = device.userAgent;
381
+ this.populateSafeAreaEditor(editor, device);
280
382
  let uaType;
281
383
  if (device.mobile()) {
282
384
  uaType =
@@ -292,6 +394,33 @@ export class DevicesSettingsTab extends UI.Widget.VBox implements
292
394
  return editor;
293
395
  }
294
396
 
397
+ private safeAreaInsetsFromEditor(editor: UI.ListWidget.Editor<EmulationModel.EmulatedDevices.EmulatedDevice>,
398
+ controlPrefix = ''): EmulationModel.DeviceModeModel.Insets|null {
399
+ const left = this.editorIntegerValue(editor, `${controlPrefix}safe-area-left`);
400
+ const top = this.editorIntegerValue(editor, `${controlPrefix}safe-area-top`);
401
+ const right = this.editorIntegerValue(editor, `${controlPrefix}safe-area-right`);
402
+ const bottom = this.editorIntegerValue(editor, `${controlPrefix}safe-area-bottom`);
403
+ if (!left && !top && !right && !bottom) {
404
+ return null;
405
+ }
406
+ return new EmulationModel.DeviceModeModel.Insets(left, top, right, bottom);
407
+ }
408
+
409
+ private populateSafeAreaEditor(editor: UI.ListWidget.Editor<EmulationModel.EmulatedDevices.EmulatedDevice>,
410
+ device: EmulationModel.EmulatedDevices.EmulatedDevice): void {
411
+ const safeAreaInsets = this.verticalMode(device)?.safeAreaInsets;
412
+ editor.control('safe-area-left').value = this.toNumericInputValue(safeAreaInsets?.left || 0);
413
+ editor.control('safe-area-top').value = this.toNumericInputValue(safeAreaInsets?.top || 0);
414
+ editor.control('safe-area-right').value = this.toNumericInputValue(safeAreaInsets?.right || 0);
415
+ editor.control('safe-area-bottom').value = this.toNumericInputValue(safeAreaInsets?.bottom || 0);
416
+
417
+ const landscapeSafeAreaInsets = this.horizontalMode(device)?.safeAreaInsets;
418
+ editor.control('landscape-safe-area-left').value = this.toNumericInputValue(landscapeSafeAreaInsets?.left || 0);
419
+ editor.control('landscape-safe-area-top').value = this.toNumericInputValue(landscapeSafeAreaInsets?.top || 0);
420
+ editor.control('landscape-safe-area-right').value = this.toNumericInputValue(landscapeSafeAreaInsets?.right || 0);
421
+ editor.control('landscape-safe-area-bottom').value = this.toNumericInputValue(landscapeSafeAreaInsets?.bottom || 0);
422
+ }
423
+
295
424
  private createEditor(): UI.ListWidget.Editor<EmulationModel.EmulatedDevices.EmulatedDevice> {
296
425
  if (this.editor) {
297
426
  return this.editor;
@@ -313,6 +442,11 @@ export class DevicesSettingsTab extends UI.Widget.VBox implements
313
442
  dpr.classList.add('device-edit-fixed');
314
443
  screen.appendChild(dpr);
315
444
 
445
+ this.appendSafeAreaFields(editor, deviceFields, i18nString(UIStrings.portraitSafeArea), '',
446
+ portraitSafeAreaValidator);
447
+ this.appendSafeAreaFields(editor, deviceFields, i18nString(UIStrings.landscapeSafeArea), 'landscape-',
448
+ landscapeSafeAreaValidator);
449
+
316
450
  const uaStringFields = content.createChild('div', 'devices-edit-fields');
317
451
  UI.UIUtils.createTextChild(uaStringFields.createChild('b'), i18nString(UIStrings.userAgentString));
318
452
 
@@ -389,5 +523,53 @@ export class DevicesSettingsTab extends UI.Widget.VBox implements
389
523
  input: UI.ListWidget.EditorControl): UI.ListWidget.ValidatorResult {
390
524
  return EmulationModel.DeviceModeModel.DeviceModeModel.scaleValidator(input.value);
391
525
  }
526
+
527
+ function safeAreaValidator(orientationLabel: string,
528
+ input: UI.ListWidget.EditorControl): UI.ListWidget.ValidatorResult {
529
+ if (parseOptionalNonNegativeInteger(input.value) !== null) {
530
+ return {valid: true};
531
+ }
532
+
533
+ return {
534
+ valid: false,
535
+ errorMessage: i18nString(UIStrings.safeAreaValueMustBeInRange, {
536
+ PH1: orientationLabel,
537
+ PH2: input.getAttribute('aria-label') || input.getAttribute('placeholder') || '',
538
+ PH3: EmulationModel.DeviceModeModel.MaxDeviceSize,
539
+ }),
540
+ };
541
+ }
542
+
543
+ function portraitSafeAreaValidator(_item: EmulationModel.EmulatedDevices.EmulatedDevice, _index: number,
544
+ input: UI.ListWidget.EditorControl): UI.ListWidget.ValidatorResult {
545
+ return safeAreaValidator(i18nString(UIStrings.portraitSafeArea), input);
546
+ }
547
+
548
+ function landscapeSafeAreaValidator(_item: EmulationModel.EmulatedDevices.EmulatedDevice, _index: number,
549
+ input: UI.ListWidget.EditorControl): UI.ListWidget.ValidatorResult {
550
+ return safeAreaValidator(i18nString(UIStrings.landscapeSafeArea), input);
551
+ }
552
+ }
553
+
554
+ private appendSafeAreaFields(editor: UI.ListWidget.Editor<EmulationModel.EmulatedDevices.EmulatedDevice>,
555
+ deviceFields: HTMLElement, title: string, controlPrefix: string,
556
+ safeAreaValidator:
557
+ (item: EmulationModel.EmulatedDevices.EmulatedDevice, index: number,
558
+ input: UI.ListWidget.EditorControl) => UI.ListWidget.ValidatorResult): void {
559
+ const safeAreaGroup = deviceFields.createChild('div', 'devices-edit-safe-area-group');
560
+ UI.ARIAUtils.markAsGroup(safeAreaGroup);
561
+ const heading = safeAreaGroup.createChild('b');
562
+ heading.id = UI.ARIAUtils.nextId('safe-area-heading-');
563
+ UI.UIUtils.createTextChild(heading, title);
564
+ safeAreaGroup.setAttribute('aria-labelledby', heading.id);
565
+ const safeAreaRow = safeAreaGroup.createChild('div', 'hbox');
566
+ safeAreaRow.appendChild(editor.createInput(`${controlPrefix}safe-area-left`, 'text',
567
+ i18nString(UIStrings.safeAreaLeft), safeAreaValidator));
568
+ safeAreaRow.appendChild(editor.createInput(`${controlPrefix}safe-area-top`, 'text',
569
+ i18nString(UIStrings.safeAreaTop), safeAreaValidator));
570
+ safeAreaRow.appendChild(editor.createInput(`${controlPrefix}safe-area-right`, 'text',
571
+ i18nString(UIStrings.safeAreaRight), safeAreaValidator));
572
+ safeAreaRow.appendChild(editor.createInput(`${controlPrefix}safe-area-bottom`, 'text',
573
+ i18nString(UIStrings.safeAreaBottom), safeAreaValidator));
392
574
  }
393
575
  }
@@ -9,6 +9,19 @@
9
9
  padding-right: 0;
10
10
  }
11
11
 
12
+ .device-group-container {
13
+ margin-bottom: 8px;
14
+ }
15
+
16
+ .device-group-title {
17
+ font-weight: 600;
18
+ color: var(--sys-color-on-surface-subtle);
19
+ font-size: 11px;
20
+ text-transform: uppercase;
21
+ letter-spacing: 0.5px;
22
+ margin: 12px 0 4px;
23
+ }
24
+
12
25
  .list {
13
26
  &:has(div) {
14
27
  border: none;
@@ -69,6 +82,11 @@
69
82
  margin-bottom: 5px;
70
83
  }
71
84
 
85
+ .devices-edit-safe-area-group {
86
+ display: flex;
87
+ flex-direction: column;
88
+ }
89
+
72
90
  .devices-edit-fields b {
73
91
  margin-top: 8px;
74
92
  margin-bottom: 0;
@@ -253,7 +253,6 @@ Common.Revealer.registerRevealer({
253
253
  return [
254
254
  Common.Settings.Setting,
255
255
  Root.Runtime.Experiment,
256
- Root.Runtime.HostExperiment,
257
256
  ];
258
257
  },
259
258
  async loadRevealer() {
@@ -137,8 +137,6 @@ const LOCALIZED_INSTRUMENTATION_NAMES:
137
137
  i18nLazyString(UIStrings.scriptFirstStatement),
138
138
  [SDK.EventBreakpointsModel.InstrumentationNames.SCRIPT_BLOCKED_BY_CSP]:
139
139
  i18nLazyString(UIStrings.scriptBlockedByContentSecurity),
140
- [SDK.EventBreakpointsModel.InstrumentationNames.SHARED_STORAGE_WORKLET_SCRIPT_FIRST_STATEMENT]:
141
- i18nLazyString(UIStrings.scriptFirstStatement),
142
140
  [SDK.EventBreakpointsModel.InstrumentationNames.REQUEST_ANIMATION_FRAME]:
143
141
  i18nLazyString(UIStrings.requestAnimationFrame),
144
142
  [SDK.EventBreakpointsModel.InstrumentationNames.CANCEL_ANIMATION_FRAME]:
@@ -182,11 +182,17 @@ const DEFAULT_VIEW = (input: ViewInput|null, _output: undefined, target: Documen
182
182
  type View = typeof DEFAULT_VIEW;
183
183
 
184
184
  export class DebuggerPausedMessage extends UI.Widget.Widget<ShadowRoot> {
185
+ static override readonly INJECT = [SDK.EventBreakpointsModel.EventBreakpointsManager] as const;
186
+
185
187
  #viewInput: ViewInput|null = null;
186
- constructor(element?: HTMLElement, private readonly view: View = DEFAULT_VIEW) {
188
+ readonly #eventBreakpointsManager: SDK.EventBreakpointsModel.EventBreakpointsManager;
189
+ constructor(element: HTMLElement|undefined,
190
+ [eventBreakpointsManager]: UI.Widget.WidgetDependencies<typeof DebuggerPausedMessage>,
191
+ private readonly view: View = DEFAULT_VIEW) {
187
192
  super(element, {
188
193
  useShadowDom: 'pure',
189
194
  });
195
+ this.#eventBreakpointsManager = eventBreakpointsManager;
190
196
  }
191
197
 
192
198
  private static descriptionWithoutStack(description: string): string {
@@ -221,7 +227,7 @@ export class DebuggerPausedMessage extends UI.Widget.Widget<ShadowRoot> {
221
227
  };
222
228
  }
223
229
 
224
- static #findEventNameForUi(detailsAuxData?: SDK.DebuggerModel.EventListenerPausedDetailsAuxData): string {
230
+ #findEventNameForUi(detailsAuxData?: SDK.DebuggerModel.EventListenerPausedDetailsAuxData): string {
225
231
  if (!detailsAuxData) {
226
232
  return '';
227
233
  }
@@ -237,7 +243,7 @@ export class DebuggerPausedMessage extends UI.Widget.Widget<ShadowRoot> {
237
243
  }
238
244
 
239
245
  let breakpoint: SDK.CategorizedBreakpoint.CategorizedBreakpoint|null =
240
- SDK.EventBreakpointsModel.EventBreakpointsManager.instance().resolveEventListenerBreakpoint(detailsAuxData);
246
+ this.#eventBreakpointsManager.resolveEventListenerBreakpoint(detailsAuxData);
241
247
  if (breakpoint) {
242
248
  // EventBreakpointsManager breakpoints are the only ones with localized names.
243
249
  return getLocalizedBreakpointName(breakpoint.name);
@@ -269,8 +275,8 @@ export class DebuggerPausedMessage extends UI.Widget.Widget<ShadowRoot> {
269
275
  if (details.reason === Protocol.Debugger.PausedEventReason.DOM) {
270
276
  this.#viewInput = await DebuggerPausedMessage.createDOMBreakpointHitMessageDetails(details);
271
277
  } else if (details.reason === Protocol.Debugger.PausedEventReason.EventListener) {
272
- const eventNameForUI = DebuggerPausedMessage.#findEventNameForUi(
273
- details.auxData as SDK.DebuggerModel.EventListenerPausedDetailsAuxData);
278
+ const eventNameForUI =
279
+ this.#findEventNameForUi(details.auxData as SDK.DebuggerModel.EventListenerPausedDetailsAuxData);
274
280
  this.#viewInput = {mainText: i18nString(UIStrings.pausedOnEventListener), subText: eventNameForUI, errorLike};
275
281
  } else if (details.reason === Protocol.Debugger.PausedEventReason.XHR) {
276
282
  const auxData = (details.auxData as PausedDetailsAuxData);
@@ -1773,7 +1773,7 @@ export class BreakpointLocationRevealer implements
1773
1773
  async reveal(breakpointLocation: Breakpoints.BreakpointManager.BreakpointLocation, omitFocus?: boolean|undefined):
1774
1774
  Promise<void> {
1775
1775
  const {uiLocation} = breakpointLocation;
1776
- SourcesPanel.instance().showUILocation(uiLocation, omitFocus);
1776
+ await SourcesPanel.instance().showUILocation(uiLocation, omitFocus);
1777
1777
  const debuggerPlugin = debuggerPluginForUISourceCode.get(uiLocation.uiSourceCode);
1778
1778
  if (debuggerPlugin) {
1779
1779
  debuggerPlugin.editBreakpointLocation(breakpointLocation);
@@ -15,7 +15,7 @@ export const HistoryDepth = 20;
15
15
  export class EditingLocationHistoryManager {
16
16
  private readonly entries: EditingLocationHistoryEntry[] = [];
17
17
  private current = -1;
18
- private revealing = false;
18
+ private revealingCount = 0;
19
19
 
20
20
  constructor(private readonly sourcesView: SourcesView) {
21
21
  }
@@ -31,7 +31,7 @@ export class EditingLocationHistoryManager {
31
31
  }
32
32
  const prevPos = update.startState.selection.main;
33
33
  const newPos = update.state.selection.main;
34
- const isJump = !this.revealing && prevPos.anchor !== newPos.anchor && update.transactions.some(tr => {
34
+ const isJump = this.revealingCount === 0 && prevPos.anchor !== newPos.anchor && update.transactions.some(tr => {
35
35
  return Boolean(
36
36
  tr.isUserEvent('select.pointer') || tr.isUserEvent('select.reveal') || tr.isUserEvent('select.search'));
37
37
  });
@@ -50,7 +50,7 @@ export class EditingLocationHistoryManager {
50
50
  }
51
51
 
52
52
  updateCurrentState(uiSourceCode: Workspace.UISourceCode.UISourceCode, position: number): void {
53
- if (!this.revealing) {
53
+ if (this.revealingCount === 0) {
54
54
  const top = this.current >= 0 ? this.entries[this.current] : null;
55
55
  if (top?.matches(uiSourceCode)) {
56
56
  top.position = position;
@@ -66,26 +66,29 @@ export class EditingLocationHistoryManager {
66
66
  }
67
67
  }
68
68
 
69
- private reveal(entry: EditingLocationHistoryEntry): void {
69
+ private async reveal(entry: EditingLocationHistoryEntry): Promise<void> {
70
70
  const uiSourceCode = Workspace.Workspace.WorkspaceImpl.instance().uiSourceCode(entry.projectId, entry.url);
71
71
  if (uiSourceCode) {
72
- this.revealing = true;
73
- this.sourcesView.showSourceLocation(uiSourceCode, entry.position, false, true);
74
- this.revealing = false;
72
+ this.revealingCount++;
73
+ try {
74
+ await this.sourcesView.showSourceLocation(uiSourceCode, entry.position, false, true);
75
+ } finally {
76
+ this.revealingCount--;
77
+ }
75
78
  }
76
79
  }
77
80
 
78
81
  rollback(): void {
79
82
  if (this.current > 0) {
80
83
  this.current--;
81
- this.reveal(this.entries[this.current]);
84
+ void this.reveal(this.entries[this.current]);
82
85
  }
83
86
  }
84
87
 
85
88
  rollover(): void {
86
89
  if (this.current < this.entries.length - 1) {
87
90
  this.current++;
88
- this.reveal(this.entries[this.current]);
91
+ void this.reveal(this.entries[this.current]);
89
92
  }
90
93
  }
91
94