Skip to content

Conversation

@KanishkRanjan
Copy link

Fixes #277787
This PR fixes a crash in the Settings UI triggered when interacting with the Editor: Default Formatter dropdown while VS Code is still discovering extensions during startup.

The issue occurs because this dropdown dynamically updates its schema as new formatters become available, causing repeated Settings Tree rebuilds. During this “startup storm,” the TOC (sidebar) and Main Settings Tree enter a feedback loop where they exchange stale element references.

while working on this I noticed that the Settings Editor viewport often drifts or jumps (usually by ~38px) when extensions load or configuration schemas update in the background

I implemented a scroll anchoring mechanism within onConfigUpdate to stabilize the view:

  • Capture: Right before the destructive model refresh, I capture the ID (Setting Key or Group ID) of the firstVisibleElement.
  • Restore: Immediately after the tree re-renders, I look up the equivalent element in the new model using that captured ID.
  • Snap: If the element exists, I force a reveal(element, 0) to snap the viewport back to the correct position, neutralizing any layout shift
GhostScroll.mov

…ost scrolls from early extension registrations.
@vs-code-engineering
Copy link

vs-code-engineering bot commented Nov 22, 2025

📬 CODENOTIFY

The following users are being notified based on files changed in this PR:

@rzhao271

Matched files:

  • src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts

@KanishkRanjan
Copy link
Author

@microsoft-github-policy-service agree

Update search result model and refresh settings tree on changes.
@KanishkRanjan
Copy link
Author

Sry to bother you @rzhao271, What are your reviews on this ?
This is my second pr so I am bit excited for this 😊

@rzhao271
Copy link
Collaborator

No problem. I plan to take a look on Monday.

@rzhao271 rzhao271 added this to the November 2025 milestone Nov 26, 2025
@rzhao271
Copy link
Collaborator

rzhao271 commented Dec 1, 2025

When trying Ben's steps from the original issue, I now see the following error:

selectBoxCustom.ts:519 Uncaught NotFoundError: Failed to execute 'remove' on 'Element': The node to be removed is no longer a child of this node. Perhaps it was moved in a 'blur' event handler?
    at Object.dispose (selectBoxCustom.ts:519:34)
    at ContextView.hide (contextview.ts:372:25)
    at ContextViewService.hideContextView (contextViewService.ts:65:20)
    at SettingTreeRenderers.cancelSuggesters (settingsTree.ts:2270:28)
    at SettingsEditor2.updateTreeScrollSync (settingsEditor2.ts:1205:25)
    at settingsEditor2.ts:1145:10

I'll check whether that issue also shows up before this PR. Feel free to also take a look in the meantime.

Edit: Even though there's no more console error upon selecting another table of contents entry thanks to the hasElement check, the settings list still fails to scroll to that entry. I'd prefer that the fix also resolves the desync issue itself.

@KanishkRanjan
Copy link
Author

@rzhao271 will be committing a fix it soon

Enhance settings tree element handling by searching for equivalent old objects when the current element is not found. This includes a recursive search through the tree nodes to reveal the appropriate element.
@KanishkRanjan
Copy link
Author

Sorry for that PR, and wasting your time. I was so distracted by ghost scrolling that might have overlooked the required fix.
I had added a lot of debug statements and modified many lines code before finding a fix and while trying to keep everything clean and committing minimal changes, I might have overlooked it. ( I recloned vscode and modified it by comparing previous clone, It was working in prev as ghost scroll wouldn't reproduce ).

Thank you for your time
@rzhao271 please take a look.

Screen.Recording.2025-12-02.at.10.30.12.AM.mov

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[SettingsTree] Tree element not found: [object Object]

2 participants