fix: avoid spurious 'restart terminal' prompts on every window reload#1648
Merged
Conversation
VS Code shows a 'restart terminal to apply environment variable changes' prompt whenever an extension's EnvironmentVariableCollection differs from what is already applied to running terminals. The previous No-Config Debug activation flow called collection.clear() followed by replace() / append() unconditionally, which VS Code always interprets as a change even when the resulting values are byte-identical, so the prompt fired on every window reload. Refactor the activation to diff-aware helpers (applyReplaceIfChanged, applyAppendIfChanged, deleteIfPresent) that only write to the collection when the existing mutator's type, value, or options actually differ from what we want. The hot path on a normal reload becomes a sequence of no-op get() comparisons, so VS Code never observes a change and the prompt no longer appears. Additional notes: * Compare normalized EnvironmentVariableMutatorOptions (applyAtProcessCreation / applyAtShellIntegration) so future options changes still trigger a write. * When the Java Language Server cannot resolve a Java home, keep the previously stored VSCODE_JAVA_EXEC instead of deleting it, to avoid churn caused by transient startup failures. * Explicitly clean up legacy keys (currently JAVA_TOOL_OPTIONS) that older versions of this extension used to set but no longer manage. * Set a human-readable description on the collection so users can see the source in VS Code's environment variable UI. Fixes #1647 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR fixes #1647 by making the extension’s persistent EnvironmentVariableCollection updates idempotent, so VS Code doesn’t interpret every window reload as an environment change that requires restarting terminals.
Changes:
- Added diff-aware helpers (
applyReplaceIfChanged,applyAppendIfChanged,deleteIfPresent) to avoid writing to the environment collection when nothing effectively changes. - Updated no-config debug activation to stop calling
collection.clear(), perform one-time legacy cleanup, and set a visible collection description. - Added unit tests covering mutator diffing behavior and a regression test for back-to-back activations.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
src/envVarSync.ts |
Introduces idempotent environment-variable collection update helpers with option normalization. |
src/noConfigDebugInit.ts |
Switches activation flow to diff-aware updates (no clear()), adds legacy cleanup + collection description. |
test/envVarSync.test.ts |
Adds targeted unit/regression coverage ensuring repeated activations produce zero writes when unchanged. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
chagong
reviewed
Jun 2, 2026
JAVA_TOOL_OPTIONS has never been written to the per-extension EnvironmentVariableCollection by this codebase (verified via 'git log -S JAVA_TOOL_OPTIONS'). The legacy cleanup loop was therefore dead code, and could be misread as touching user-managed env vars (it cannot — the collection is per-extension and only sees mutators this extension wrote). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
Author
|
Good catch — agreed, removed in bf7fff1. To clarify why it was safe but still worth removing:
Since the value was effectively zero and the code reads as if it might be doing something risky, dropping it is the cleaner call. PR updated. |
Production code no longer calls deleteIfPresent after the legacy cleanup loop was removed. Drop the helper and its tests rather than carry a YAGNI export — easy to reintroduce if a real caller appears. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
chagong
approved these changes
Jun 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #1647: the Debugger for Java extension prompts the user to restart their terminal every time the VS Code window is reloaded, even when nothing about the contributed environment has actually changed.
Root cause
restart terminalprompt whenever the collection differs from what was last applied to running terminals.clear()followed by a re-add is always interpreted as a change, even when the resulting set of variables is byte-identical, so the prompt fires on every reload (see Clearing an environment variable causes relaunch terminal button to get stuck vscode#95919, Ability to clear/delete a variable inside EnvironmentVariableCollection when extension is disposed/restarted vscode#234384).Fix
Introduce diff-aware helpers in
src/envVarSync.ts:applyReplaceIfChanged/applyAppendIfChanged— only callreplace/appendwhen the existing mutator's type, value, and normalized options differ from the desired ones.deleteIfPresent— only calldeletewhen a mutator exists.Rewrite the activation flow in
src/noConfigDebugInit.tsto use those helpers and drop the unconditionalclear(). On a typical reload all comparisons are no-ops, so VS Code never observes a change and never prompts.Behavioral notes
VSCODE_JAVA_EXEC. IfgetJavaHome()returns nothing (e.g., JDT LS hasn't finished initializing), we keep the previously stored value instead of deleting it, avoiding churn from transient startup hiccups.deletekeys older versions used to set but no longer manage (currently justJAVA_TOOL_OPTIONS, per the comment that was already in this file). After the first reload this is also a no-op.collection.description =Java No-Config Debug`` so the source is visible in VS Code's environment-variable UI.Tests
Added
test/envVarSync.test.tswith 13 cases covering:deleteIfPresentpresent/absentFull
npm testoutput: 24 passing, 0 failing.Risk
registerNoConfigDebugsignature unchanged.extPathdiffers (thePATHappend value embeds the extension version directory) — this is unavoidable and only happens once per upgrade.