@@ -1238,16 +1238,7 @@ export class WidgetRenderer<S> {
12381238 private readonly _pooledToastContainers : { rect : Rect ; props : ToastContainerProps } [ ] = [ ] ;
12391239 private readonly _pooledToastFocusableActionIds : string [ ] = [ ] ;
12401240 private readonly _pooledActiveExitKeys = new Set < string > ( ) ;
1241- // Pooled Sets for tracking previous IDs (GC cleanup detection)
12421241 private readonly _pooledPrevTreeIds = new Set < string > ( ) ;
1243- private readonly _pooledPrevDropdownIds = new Set < string > ( ) ;
1244- private readonly _pooledPrevVirtualListIds = new Set < string > ( ) ;
1245- private readonly _pooledPrevTableIds = new Set < string > ( ) ;
1246- private readonly _pooledPrevTreeStoreIds = new Set < string > ( ) ;
1247- private readonly _pooledPrevCommandPaletteIds = new Set < string > ( ) ;
1248- private readonly _pooledPrevToolApprovalDialogIds = new Set < string > ( ) ;
1249- private readonly _pooledPrevDiffViewerIds = new Set < string > ( ) ;
1250- private readonly _pooledPrevLogsConsoleIds = new Set < string > ( ) ;
12511242 private _runtimeBreadcrumbs : WidgetRuntimeBreadcrumbSnapshot = EMPTY_WIDGET_RUNTIME_BREADCRUMBS ;
12521243 private _constraintBreadcrumbs : RuntimeBreadcrumbConstraintsSummary | null = null ;
12531244 private _constraintExprIndexByInstanceId : ReadonlyMap <
@@ -4285,37 +4276,27 @@ export class WidgetRenderer<S> {
42854276 }
42864277 }
42874278
4288- if ( doCommit && ( hasRoutingWidgets || hadRoutingWidgets ) ) {
4279+ const canSkipFullRoutingRebuildOnCommit =
4280+ doCommit &&
4281+ hadRoutingWidgets &&
4282+ hasRoutingWidgets &&
4283+ identityDamageFromCommit !== null &&
4284+ identityDamageFromCommit . routingRelevantChanged === false ;
4285+
4286+ if (
4287+ doCommit &&
4288+ ( hasRoutingWidgets || hadRoutingWidgets ) &&
4289+ ! canSkipFullRoutingRebuildOnCommit
4290+ ) {
42894291 didRoutingRebuild = true ;
42904292 this . hadRoutingWidgets = hasRoutingWidgets ;
42914293 const routingToken = PERF_DETAIL_ENABLED ? perfMarkStart ( "routing_rebuild" ) : 0 ;
42924294 const getRectForInstance = ( instanceId : InstanceId ) =>
42934295 this . _pooledRectByInstanceId . get ( instanceId ) ?? ZERO_RECT ;
42944296
42954297 // Rebuild complex widget metadata maps (id -> props) for routing.
4296- // Use pooled Sets to track previous IDs for GC cleanup detection (avoids per-frame allocations).
42974298 this . _pooledPrevTreeIds . clear ( ) ;
4298- for ( const k of this . treeById . keys ( ) ) this . _pooledPrevTreeIds . add ( k ) ;
4299- this . _pooledPrevDropdownIds . clear ( ) ;
4300- for ( const k of this . dropdownById . keys ( ) ) this . _pooledPrevDropdownIds . add ( k ) ;
4301- this . _pooledPrevVirtualListIds . clear ( ) ;
4302- for ( const k of this . virtualListById . keys ( ) ) this . _pooledPrevVirtualListIds . add ( k ) ;
4303- this . _pooledPrevTableIds . clear ( ) ;
4304- for ( const k of this . tableById . keys ( ) ) this . _pooledPrevTableIds . add ( k ) ;
4305- this . _pooledPrevTreeStoreIds . clear ( ) ;
4306- for ( const k of this . treeById . keys ( ) ) this . _pooledPrevTreeStoreIds . add ( k ) ;
4307- for ( const k of this . filePickerById . keys ( ) ) this . _pooledPrevTreeStoreIds . add ( k ) ;
4308- for ( const k of this . fileTreeExplorerById . keys ( ) ) this . _pooledPrevTreeStoreIds . add ( k ) ;
4309- this . _pooledPrevCommandPaletteIds . clear ( ) ;
4310- for ( const k of this . commandPaletteById . keys ( ) ) this . _pooledPrevCommandPaletteIds . add ( k ) ;
4311- this . _pooledPrevToolApprovalDialogIds . clear ( ) ;
4312- for ( const k of this . toolApprovalDialogById . keys ( ) )
4313- this . _pooledPrevToolApprovalDialogIds . add ( k ) ;
4314- this . _pooledPrevDiffViewerIds . clear ( ) ;
4315- for ( const k of this . diffViewerById . keys ( ) ) this . _pooledPrevDiffViewerIds . add ( k ) ;
4316- this . _pooledPrevLogsConsoleIds . clear ( ) ;
4317- for ( const k of this . logsConsoleById . keys ( ) ) this . _pooledPrevLogsConsoleIds . add ( k ) ;
4318-
4299+ for ( const treeId of this . treeById . keys ( ) ) this . _pooledPrevTreeIds . add ( treeId ) ;
43194300 this . virtualListById . clear ( ) ;
43204301 this . buttonById . clear ( ) ;
43214302 this . linkById . clear ( ) ;
@@ -4567,9 +4548,9 @@ export class WidgetRenderer<S> {
45674548 this . closeOnEscapeByLayerId = this . _pooledCloseOnEscape ;
45684549 this . closeOnBackdropByLayerId = this . _pooledCloseOnBackdrop ;
45694550 this . onCloseByLayerId = this . _pooledOnClose ;
4570- this . dropdownStack = Object . freeze ( this . _pooledDropdownStack . slice ( ) ) ;
4571- this . overlayShortcutOwners = Object . freeze ( this . _pooledOverlayShortcutOwners . slice ( ) ) ;
4572- this . toastContainers = Object . freeze ( this . _pooledToastContainers . slice ( ) ) ;
4551+ this . dropdownStack = this . _pooledDropdownStack . slice ( ) ;
4552+ this . overlayShortcutOwners = this . _pooledOverlayShortcutOwners . slice ( ) ;
4553+ this . toastContainers = this . _pooledToastContainers . slice ( ) ;
45734554 this . rebuildOverlayShortcutBindings ( ) ;
45744555
45754556 // Build toast action maps using pooled collections.
@@ -4598,7 +4579,7 @@ export class WidgetRenderer<S> {
45984579
45994580 this . toastActionByFocusId = this . _pooledToastActionByFocusId ;
46004581 this . toastActionLabelByFocusId = this . _pooledToastActionLabelByFocusId ;
4601- this . toastFocusableActionIds = Object . freeze ( this . _pooledToastFocusableActionIds . slice ( ) ) ;
4582+ this . toastFocusableActionIds = this . _pooledToastFocusableActionIds . slice ( ) ;
46024583
46034584 const baseFocusList = this . baseFocusList ;
46044585 const baseEnabledById = this . baseEnabledById ;
@@ -4799,8 +4780,8 @@ export class WidgetRenderer<S> {
47994780 this . closeOnEscapeByLayerId = this . _pooledCloseOnEscape ;
48004781 this . closeOnBackdropByLayerId = this . _pooledCloseOnBackdrop ;
48014782 this . onCloseByLayerId = this . _pooledOnClose ;
4802- this . dropdownStack = Object . freeze ( this . _pooledDropdownStack . slice ( ) ) ;
4803- this . toastContainers = Object . freeze ( this . _pooledToastContainers . slice ( ) ) ;
4783+ this . dropdownStack = this . _pooledDropdownStack . slice ( ) ;
4784+ this . toastContainers = this . _pooledToastContainers . slice ( ) ;
48044785 this . rebuildOverlayShortcutBindings ( ) ;
48054786
48064787 this . _pooledToastActionByFocusId . clear ( ) ;
@@ -4828,7 +4809,7 @@ export class WidgetRenderer<S> {
48284809
48294810 this . toastActionByFocusId = this . _pooledToastActionByFocusId ;
48304811 this . toastActionLabelByFocusId = this . _pooledToastActionLabelByFocusId ;
4831- this . toastFocusableActionIds = Object . freeze ( this . _pooledToastFocusableActionIds . slice ( ) ) ;
4812+ this . toastFocusableActionIds = this . _pooledToastFocusableActionIds . slice ( ) ;
48324813
48334814 const baseFocusList = this . baseFocusList ;
48344815 const baseEnabledById = this . baseEnabledById ;
@@ -4860,6 +4841,12 @@ export class WidgetRenderer<S> {
48604841
48614842 if ( doCommit && ! didRoutingRebuild ) {
48624843 this . hadRoutingWidgets = hasRoutingWidgets ;
4844+ if ( canSkipFullRoutingRebuildOnCommit && ! doLayout ) {
4845+ // Full routing rebuild usually refreshes shortcut bindings. When this
4846+ // fast path skips that rebuild on commit-only turns, keep shortcut
4847+ // bindings in sync with async command palette item updates.
4848+ this . rebuildOverlayShortcutBindings ( ) ;
4849+ }
48634850 }
48644851
48654852 if ( doCommit && didRoutingRebuild ) {
@@ -4896,27 +4883,21 @@ export class WidgetRenderer<S> {
48964883 }
48974884
48984885 // Garbage collect per-dropdown routing state for dropdowns that were removed.
4899- for ( const prevDropdownId of this . _pooledPrevDropdownIds ) {
4900- if ( ! this . dropdownById . has ( prevDropdownId ) ) {
4901- this . dropdownSelectedIndexById . delete ( prevDropdownId ) ;
4902- }
4886+ for ( const dropdownId of this . dropdownSelectedIndexById . keys ( ) ) {
4887+ if ( ! this . dropdownById . has ( dropdownId ) ) this . dropdownSelectedIndexById . delete ( dropdownId ) ;
49034888 }
49044889
49054890 // Garbage collect local state for virtual lists that were removed.
4906- for ( const prevId of this . _pooledPrevVirtualListIds ) {
4907- if ( ! this . virtualListById . has ( prevId ) ) {
4908- this . virtualListStore . delete ( prevId ) ;
4909- if ( this . pressedVirtualList ?. id === prevId ) {
4910- this . pressedVirtualList = null ;
4911- }
4912- }
4891+ for ( const virtualListId of this . virtualListStore . keys ( ) ) {
4892+ if ( ! this . virtualListById . has ( virtualListId ) ) this . virtualListStore . delete ( virtualListId ) ;
4893+ }
4894+ if ( this . pressedVirtualList && ! this . virtualListById . has ( this . pressedVirtualList . id ) ) {
4895+ this . pressedVirtualList = null ;
49134896 }
49144897
49154898 // Garbage collect local state for tables that were removed.
4916- for ( const prevId of this . _pooledPrevTableIds ) {
4917- if ( ! this . tableById . has ( prevId ) ) {
4918- this . tableStore . delete ( prevId ) ;
4919- }
4899+ for ( const tableId of this . tableStore . keys ( ) ) {
4900+ if ( ! this . tableById . has ( tableId ) ) this . tableStore . delete ( tableId ) ;
49204901 }
49214902
49224903 // Garbage collect per-tree lazy-loading caches for trees that were removed.
@@ -4931,13 +4912,13 @@ export class WidgetRenderer<S> {
49314912 }
49324913
49334914 // Garbage collect treeStore entries for tree-like widgets that were removed.
4934- for ( const prevId of this . _pooledPrevTreeStoreIds ) {
4915+ for ( const treeLikeId of this . treeStore . keys ( ) ) {
49354916 if (
4936- ! this . treeById . has ( prevId ) &&
4937- ! this . filePickerById . has ( prevId ) &&
4938- ! this . fileTreeExplorerById . has ( prevId )
4917+ ! this . treeById . has ( treeLikeId ) &&
4918+ ! this . filePickerById . has ( treeLikeId ) &&
4919+ ! this . fileTreeExplorerById . has ( treeLikeId )
49394920 ) {
4940- this . treeStore . delete ( prevId ) ;
4921+ this . treeStore . delete ( treeLikeId ) ;
49414922 }
49424923 }
49434924
@@ -4962,33 +4943,35 @@ export class WidgetRenderer<S> {
49624943 }
49634944
49644945 // Garbage collect command palette async state for palettes that were removed.
4965- for ( const prevId of this . _pooledPrevCommandPaletteIds ) {
4966- if ( ! this . commandPaletteById . has ( prevId ) ) {
4967- this . commandPaletteItemsById . delete ( prevId ) ;
4968- this . commandPaletteLoadingById . delete ( prevId ) ;
4969- this . commandPaletteFetchTokenById . delete ( prevId ) ;
4970- this . commandPaletteLastQueryById . delete ( prevId ) ;
4971- this . commandPaletteLastSourcesRefById . delete ( prevId ) ;
4972- }
4946+ for ( const id of this . commandPaletteItemsById . keys ( ) ) {
4947+ if ( ! this . commandPaletteById . has ( id ) ) this . commandPaletteItemsById . delete ( id ) ;
4948+ }
4949+ for ( const id of this . commandPaletteLoadingById . keys ( ) ) {
4950+ if ( ! this . commandPaletteById . has ( id ) ) this . commandPaletteLoadingById . delete ( id ) ;
4951+ }
4952+ for ( const id of this . commandPaletteFetchTokenById . keys ( ) ) {
4953+ if ( ! this . commandPaletteById . has ( id ) ) this . commandPaletteFetchTokenById . delete ( id ) ;
4954+ }
4955+ for ( const id of this . commandPaletteLastQueryById . keys ( ) ) {
4956+ if ( ! this . commandPaletteById . has ( id ) ) this . commandPaletteLastQueryById . delete ( id ) ;
4957+ }
4958+ for ( const id of this . commandPaletteLastSourcesRefById . keys ( ) ) {
4959+ if ( ! this . commandPaletteById . has ( id ) ) this . commandPaletteLastSourcesRefById . delete ( id ) ;
49734960 }
49744961
4975- for ( const prevId of this . _pooledPrevToolApprovalDialogIds ) {
4976- if ( ! this . toolApprovalDialogById . has ( prevId ) ) {
4977- this . toolApprovalFocusedActionById . delete ( prevId ) ;
4978- }
4962+ for ( const id of this . toolApprovalFocusedActionById . keys ( ) ) {
4963+ if ( ! this . toolApprovalDialogById . has ( id ) ) this . toolApprovalFocusedActionById . delete ( id ) ;
49794964 }
49804965
4981- for ( const prevId of this . _pooledPrevDiffViewerIds ) {
4982- if ( ! this . diffViewerById . has ( prevId ) ) {
4983- this . diffViewerFocusedHunkById . delete ( prevId ) ;
4984- this . diffViewerExpandedHunksById . delete ( prevId ) ;
4985- }
4966+ for ( const id of this . diffViewerFocusedHunkById . keys ( ) ) {
4967+ if ( ! this . diffViewerById . has ( id ) ) this . diffViewerFocusedHunkById . delete ( id ) ;
4968+ }
4969+ for ( const id of this . diffViewerExpandedHunksById . keys ( ) ) {
4970+ if ( ! this . diffViewerById . has ( id ) ) this . diffViewerExpandedHunksById . delete ( id ) ;
49864971 }
49874972
4988- for ( const prevId of this . _pooledPrevLogsConsoleIds ) {
4989- if ( ! this . logsConsoleById . has ( prevId ) ) {
4990- this . logsConsoleLastGTimeById . delete ( prevId ) ;
4991- }
4973+ for ( const id of this . logsConsoleLastGTimeById . keys ( ) ) {
4974+ if ( ! this . logsConsoleById . has ( id ) ) this . logsConsoleLastGTimeById . delete ( id ) ;
49924975 }
49934976 }
49944977
0 commit comments