# Objective Zed eagerly fetches variables for every scope returned by a DAP `scopes` response, including scopes the adapter marked `expensive: true`. Per the [DAP spec](https://microsoft.github.io/debug-adapter-protocol/specification#Types_Scope), `expensive` means "the number of variables in this scope is large or expensive to retrieve... recommended for UIs to not automatically expand and evaluate the scope. Some debug adapters (e.g. `vscode-js-debug`, used for JavaScript/Chrome debugging) mark scopes like "Global" as expensive because resolving them can hang forever. VS Code honors this and leaves the scope collapsed until the user opts in by expanding it; Zed did not, so any session with a hanging expensive scope would freeze the entire debug session (including Resume) with no user action at all. Fixes #61105 ## Solution - `Session::scopes()` in `crates/project/src/debugger/session.rs` [unconditionally called `this.variables(...)`](https://github.com/zed-industries/zed/blob/058f01fa93503491a735bfded53e77bfaa276148/crates/project/src/debugger/session.rs#L2538) for every scope in the `scopes` response. - `VariableList::build_entries()` in `crates/debugger_ui/src/session/running/variable_list.rs` also called `session.variables(...)` [on every scope](https://github.com/zed-industries/zed/blob/058f01fa93503491a735bfded53e77bfaa276148/crates/debugger_ui/src/session/running/variable_list.rs#L291-L304), as a side effect of checking whether it was empty (used to decide whether to hide it from the tree). Fixing only the first call site wasn't enough, since this one would still trigger the fetch on the very next render. Both now skip the fetch for `expensive` scopes. Expensive scopes still show up in the variable list, collapsed, so the user can expand them manually (which fetches lazily via the existing on-toggle path). Also hardened the auto-expand heuristic (e.g. "expand the only scope if it's not Locals") to never auto-expand an expensive scope, even in adapters where it happens to be the sole or "Locals"-named scope. ## Testing - Added `test_expensive_scope_is_not_eagerly_fetched` in `crates/debugger_ui/src/tests/variable_list.rs`, asserting the DAP `variables` request is never sent for an `expensive: true` scope until the user expands it, and that expanding it does trigger the fetch. Verified this test fails on the old code and passes with the fix. - Ran the full `debugger_ui` test suite, all pass, no regressions. - Manually reproduced and verified the fix using the minimal repro at https://github.com/jasonwilliams/zed-dap-repro ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable ## Showcase Before: https://github.com/user-attachments/assets/7a3ead7e-aece-4726-883d-d60d49c83b7c Here you can see that once the break has happened Zed has crashed, resuming doesn't help, i effectively need to kill the whole debug session. After: https://github.com/user-attachments/assets/7a36cbb0-f22b-4782-9326-9ccab9297fc7 Here you can see the Global scope is closed and clicking resume carries on without any crashes Release Notes: - Fixed debugger eagerly fetching expensive variable scopes --------- Co-authored-by: Anthony Eid <anthony@zed.dev>
3 files changedLine totals unavailable