Skip to content

Commit 370b5cd

Browse files
edvilmeCopilot
andcommitted
refactor: make setEnvironmentAndWait truly event-driven
Instead of draining setImmediate ticks, the helper now checks whether the environment will actually change by comparing current vs target envId. If a change is expected, it subscribes to onDidChangeEnvironment and awaits the event. If no change is expected (idempotent set), it calls setEnvironment and returns immediately — no ticks, no polling. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent c5a53c7 commit 370b5cd

1 file changed

Lines changed: 21 additions & 21 deletions

File tree

src/test/integration/interpreterSelection.integration.test.ts

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,11 @@ import { waitForCondition } from '../testUtils';
3030
/**
3131
* Calls setEnvironment and waits for the async event chain to fully settle.
3232
*
33-
* Subscribes to onDidChangeEnvironment BEFORE calling setEnvironment, then
34-
* waits for the event to fire. For idempotent sets (env already matches the
35-
* cache), no event fires — the drain fallback ensures we don't hang.
33+
* Compares the current environment with the target to determine whether
34+
* a change event is expected. If a change is expected, subscribes to
35+
* onDidChangeEnvironment BEFORE calling setEnvironment and awaits the
36+
* event. If no change is expected (idempotent set), calls setEnvironment
37+
* and returns immediately.
3638
*
3739
* Returns all captured events, which callers can inspect to verify
3840
* event payloads (e.g., old/new values).
@@ -42,9 +44,22 @@ async function setEnvironmentAndWait(
4244
scope: SetEnvironmentScope,
4345
env: PythonEnvironment | undefined,
4446
): Promise<DidChangeEnvironmentEventArgs[]> {
45-
const events: DidChangeEnvironmentEventArgs[] = [];
47+
// Determine if this set will actually change the environment.
48+
// For array scopes, check the first URI (the primary project).
49+
const getScope = Array.isArray(scope) ? scope[0] : scope;
50+
const current = await api.getEnvironment(getScope);
51+
const currentId = current?.envId.id;
52+
const targetId = env?.envId.id;
53+
const expectsChange = currentId !== targetId;
54+
55+
if (!expectsChange) {
56+
// Idempotent set — no event will fire, just call and return
57+
await api.setEnvironment(scope, env);
58+
return [];
59+
}
4660

47-
// Promise that resolves as soon as the first event fires
61+
// A change is expected — wait for the event
62+
const events: DidChangeEnvironmentEventArgs[] = [];
4863
let resolveEvent: () => void;
4964
const eventPromise = new Promise<void>((resolve) => {
5065
resolveEvent = resolve;
@@ -57,22 +72,7 @@ async function setEnvironmentAndWait(
5772

5873
try {
5974
await api.setEnvironment(scope, env);
60-
61-
// Drain fallback: 5 setImmediate ticks covers the full async chain.
62-
// For idempotent sets (no event), this ensures we don't hang.
63-
const drainPromise = (async () => {
64-
for (let tick = 0; tick < 5; tick++) {
65-
await new Promise<void>((resolve) => setImmediate(resolve));
66-
}
67-
})();
68-
69-
// Wait for the event OR drain (whichever comes first)
70-
await Promise.race([eventPromise, drainPromise]);
71-
72-
// Always drain remaining ticks to catch secondary events
73-
// (e.g., refreshEnvironment firing after the initial event)
74-
await drainPromise;
75-
75+
await eventPromise;
7676
return events;
7777
} finally {
7878
disposable.dispose();

0 commit comments

Comments
 (0)