Skip to content

Commit 1ffa23a

Browse files
authored
Ensure we register for interpreter change when moving from untrusted to trusted. (#19351)
* Ensure we register for interpreter change when moving from untrusted to trusted. * Tweak LanguageServerChangeHandler dispose * Use disposables instead on context.subscriptions for consistency. * Address comments. * Fix tests.
1 parent 35ec30f commit 1ffa23a

File tree

5 files changed

+75
-55
lines changed

5 files changed

+75
-55
lines changed

src/client/activation/node/lspNotebooksExperiment.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { inject, injectable } from 'inversify';
44
import * as semver from 'semver';
55
import { Disposable, extensions } from 'vscode';
6-
import { IConfigurationService } from '../../common/types';
6+
import { IConfigurationService, IDisposableRegistry } from '../../common/types';
77
import { sendTelemetryEvent } from '../../telemetry';
88
import { EventName } from '../../telemetry/constants';
99
import { JUPYTER_EXTENSION_ID, PYLANCE_EXTENSION_ID } from '../../common/constants';
@@ -28,16 +28,18 @@ export class LspNotebooksExperiment implements IExtensionSingleActivationService
2828
constructor(
2929
@inject(IServiceContainer) private readonly serviceContainer: IServiceContainer,
3030
@inject(IConfigurationService) private readonly configurationService: IConfigurationService,
31+
@inject(IDisposableRegistry) private readonly disposables: IDisposableRegistry,
3132
@inject(IJupyterExtensionDependencyManager) jupyterDependencyManager: IJupyterExtensionDependencyManager,
3233
) {
33-
if (!LspNotebooksExperiment.isPylanceInstalled()) {
34-
this.pylanceExtensionChangeHandler = extensions.onDidChange(this.pylanceExtensionsChangeHandler.bind(this));
35-
}
36-
3734
this.isJupyterInstalled = jupyterDependencyManager.isJupyterExtensionInstalled;
3835
}
3936

4037
public async activate(): Promise<void> {
38+
if (!LspNotebooksExperiment.isPylanceInstalled()) {
39+
this.pylanceExtensionChangeHandler = extensions.onDidChange(this.pylanceExtensionsChangeHandler.bind(this));
40+
this.disposables.push(this.pylanceExtensionChangeHandler);
41+
}
42+
4143
this.updateExperimentSupport();
4244
}
4345

src/client/extensionActivation.ts

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -159,27 +159,25 @@ async function activateLegacy(ext: ExtensionState): Promise<ActivationResult> {
159159

160160
serviceManager.get<ICodeExecutionManager>(ICodeExecutionManager).registerCommands();
161161

162-
context.subscriptions.push(new LinterCommands(serviceManager));
162+
disposables.push(new LinterCommands(serviceManager));
163163

164164
if (
165165
pythonSettings &&
166166
pythonSettings.formatting &&
167167
pythonSettings.formatting.provider !== 'internalConsole'
168168
) {
169169
const formatProvider = new PythonFormattingEditProvider(context, serviceContainer);
170-
context.subscriptions.push(languages.registerDocumentFormattingEditProvider(PYTHON, formatProvider));
171-
context.subscriptions.push(
172-
languages.registerDocumentRangeFormattingEditProvider(PYTHON, formatProvider),
173-
);
170+
disposables.push(languages.registerDocumentFormattingEditProvider(PYTHON, formatProvider));
171+
disposables.push(languages.registerDocumentRangeFormattingEditProvider(PYTHON, formatProvider));
174172
}
175173

176-
context.subscriptions.push(new ReplProvider(serviceContainer));
174+
disposables.push(new ReplProvider(serviceContainer));
177175

178176
const terminalProvider = new TerminalProvider(serviceContainer);
179177
terminalProvider.initialize(window.activeTerminal).ignoreErrors();
180-
context.subscriptions.push(terminalProvider);
178+
disposables.push(terminalProvider);
181179

182-
context.subscriptions.push(
180+
disposables.push(
183181
languages.registerCodeActionsProvider(PYTHON, new PythonCodeActionProvider(), {
184182
providedCodeActionKinds: [CodeActionKind.SourceOrganizeImports],
185183
}),
@@ -188,9 +186,7 @@ async function activateLegacy(ext: ExtensionState): Promise<ActivationResult> {
188186
serviceContainer
189187
.getAll<DebugConfigurationProvider>(IDebugConfigurationService)
190188
.forEach((debugConfigProvider) => {
191-
context.subscriptions.push(
192-
debug.registerDebugConfigurationProvider(DebuggerTypeName, debugConfigProvider),
193-
);
189+
disposables.push(debug.registerDebugConfigurationProvider(DebuggerTypeName, debugConfigProvider));
194190
});
195191

196192
serviceContainer.get<IDebuggerBanner>(IDebuggerBanner).initialize();
@@ -200,7 +196,7 @@ async function activateLegacy(ext: ExtensionState): Promise<ActivationResult> {
200196
// "activate" everything else
201197

202198
const manager = serviceContainer.get<IExtensionActivationManager>(IExtensionActivationManager);
203-
context.subscriptions.push(manager);
199+
disposables.push(manager);
204200

205201
const activationPromise = manager.activate();
206202

src/client/extensionInit.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,16 @@ export function initializeGlobals(
5454
serviceManager.addSingletonInstance<IExtensionContext>(IExtensionContext, context);
5555

5656
const standardOutputChannel = window.createOutputChannel(OutputChannelNames.python);
57-
context.subscriptions.push(standardOutputChannel);
58-
context.subscriptions.push(registerLogger(new OutputChannelLogger(standardOutputChannel)));
57+
disposables.push(standardOutputChannel);
58+
disposables.push(registerLogger(new OutputChannelLogger(standardOutputChannel)));
5959

6060
const workspaceService = new WorkspaceService();
6161
const unitTestOutChannel =
6262
workspaceService.isVirtualWorkspace || !workspaceService.isTrusted
6363
? // Do not create any test related output UI when using virtual workspaces.
6464
instance(mock<IOutputChannel>())
6565
: window.createOutputChannel(OutputChannelNames.pythonTest);
66-
context.subscriptions.push(unitTestOutChannel);
66+
disposables.push(unitTestOutChannel);
6767

6868
serviceManager.addSingletonInstance<OutputChannel>(IOutputChannel, standardOutputChannel, STANDARD_OUTPUT_CHANNEL);
6969
serviceManager.addSingletonInstance<OutputChannel>(IOutputChannel, unitTestOutChannel, TEST_OUTPUT_CHANNEL);

src/client/languageServer/watcher.ts

Lines changed: 40 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export class LanguageServerWatcher
5959
// When using Pylance, there will only be one language server for the project.
6060
private workspaceLanguageServers: Map<string, ILanguageServerExtensionManager | undefined>;
6161

62-
private languageServerChangeHandler: LanguageServerChangeHandler;
62+
private registered = false;
6363

6464
constructor(
6565
@inject(IServiceContainer) private readonly serviceContainer: IServiceContainer,
@@ -81,41 +81,12 @@ export class LanguageServerWatcher
8181
this.workspaceInterpreters = new Map();
8282
this.workspaceLanguageServers = new Map();
8383
this.languageServerType = this.configurationService.getSettings().languageServer;
84-
85-
disposables.push(this.workspaceService.onDidChangeConfiguration(this.onDidChangeConfiguration.bind(this)));
86-
87-
disposables.push(
88-
this.workspaceService.onDidChangeWorkspaceFolders(this.onDidChangeWorkspaceFolders.bind(this)),
89-
);
90-
91-
disposables.push(
92-
this.interpreterService.onDidChangeInterpreterInformation(this.onDidChangeInterpreterInformation, this),
93-
);
94-
95-
if (this.workspaceService.isTrusted) {
96-
disposables.push(this.interpreterPathService.onDidChange(this.onDidChangeInterpreter.bind(this)));
97-
}
98-
99-
this.languageServerChangeHandler = new LanguageServerChangeHandler(
100-
this.languageServerType,
101-
this.extensions,
102-
this.applicationShell,
103-
this.commandManager,
104-
this.workspaceService,
105-
this.configurationService,
106-
);
107-
disposables.push(this.languageServerChangeHandler);
108-
109-
disposables.push(
110-
extensions.onDidChange(async () => {
111-
await this.extensionsChangeHandler();
112-
}),
113-
);
11484
}
11585

11686
// IExtensionActivationService
11787

11888
public async activate(resource?: Resource): Promise<void> {
89+
this.register();
11990
await this.startLanguageServer(this.languageServerType, resource);
12091
}
12192

@@ -124,6 +95,44 @@ export class LanguageServerWatcher
12495
await this.startAndGetLanguageServer(languageServerType, resource);
12596
}
12697

98+
public register(): void {
99+
if (!this.registered) {
100+
this.registered = true;
101+
this.disposables.push(
102+
this.workspaceService.onDidChangeConfiguration(this.onDidChangeConfiguration.bind(this)),
103+
);
104+
105+
this.disposables.push(
106+
this.workspaceService.onDidChangeWorkspaceFolders(this.onDidChangeWorkspaceFolders.bind(this)),
107+
);
108+
109+
this.disposables.push(
110+
this.interpreterService.onDidChangeInterpreterInformation(this.onDidChangeInterpreterInformation, this),
111+
);
112+
113+
if (this.workspaceService.isTrusted) {
114+
this.disposables.push(this.interpreterPathService.onDidChange(this.onDidChangeInterpreter.bind(this)));
115+
}
116+
117+
this.disposables.push(
118+
this.extensions.onDidChange(async () => {
119+
await this.extensionsChangeHandler();
120+
}),
121+
);
122+
123+
this.disposables.push(
124+
new LanguageServerChangeHandler(
125+
this.languageServerType,
126+
this.extensions,
127+
this.applicationShell,
128+
this.commandManager,
129+
this.workspaceService,
130+
this.configurationService,
131+
),
132+
);
133+
}
134+
}
135+
127136
private async startAndGetLanguageServer(
128137
languageServerType: LanguageServerType,
129138
resource?: Resource,

src/test/languageServer/watcher.unit.test.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ suite('Language server watcher', () => {
8383
{} as LspNotebooksExperiment,
8484
disposables,
8585
);
86+
87+
watcher.register();
8688
});
8789

8890
teardown(() => {
@@ -131,7 +133,7 @@ suite('Language server watcher', () => {
131133
{} as LspNotebooksExperiment,
132134
disposables,
133135
);
134-
136+
watcher.register();
135137
assert.strictEqual(disposables.length, 11);
136138
});
137139

@@ -177,7 +179,7 @@ suite('Language server watcher', () => {
177179
{} as LspNotebooksExperiment,
178180
disposables,
179181
);
180-
182+
watcher.register();
181183
assert.strictEqual(disposables.length, 10);
182184
});
183185

@@ -254,6 +256,7 @@ suite('Language server watcher', () => {
254256
{} as LspNotebooksExperiment,
255257
disposables,
256258
);
259+
watcher.register();
257260

258261
// First start, get the reference to the extension manager.
259262
await watcher.startLanguageServer(LanguageServerType.None);
@@ -330,6 +333,7 @@ suite('Language server watcher', () => {
330333
{} as LspNotebooksExperiment,
331334
disposables,
332335
);
336+
watcher.register();
333337

334338
await watcher.startLanguageServer(LanguageServerType.None);
335339

@@ -409,7 +413,7 @@ suite('Language server watcher', () => {
409413
{} as LspNotebooksExperiment,
410414
disposables,
411415
);
412-
416+
watcher.register();
413417
const startLanguageServerSpy = sandbox.spy(watcher, 'startLanguageServer');
414418

415419
await watcher.startLanguageServer(LanguageServerType.None);
@@ -479,6 +483,7 @@ suite('Language server watcher', () => {
479483
{} as LspNotebooksExperiment,
480484
disposables,
481485
);
486+
watcher.register();
482487

483488
// Use a fake here so we don't actually start up language servers.
484489
const startLanguageServerFake = sandbox.fake.resolves(undefined);
@@ -542,7 +547,7 @@ suite('Language server watcher', () => {
542547
{} as LspNotebooksExperiment,
543548
disposables,
544549
);
545-
550+
watcher.register();
546551
await watcher.startLanguageServer(LanguageServerType.Jedi);
547552

548553
assert.ok(startLanguageServerStub.calledOnce);
@@ -606,6 +611,7 @@ suite('Language server watcher', () => {
606611
{} as LspNotebooksExperiment,
607612
disposables,
608613
);
614+
watcher.register();
609615

610616
await watcher.startLanguageServer(LanguageServerType.Node);
611617

@@ -664,6 +670,7 @@ suite('Language server watcher', () => {
664670
{} as LspNotebooksExperiment,
665671
disposables,
666672
);
673+
watcher.register();
667674

668675
await watcher.startLanguageServer(LanguageServerType.Jedi);
669676

@@ -753,6 +760,7 @@ suite('Language server watcher', () => {
753760
{} as LspNotebooksExperiment,
754761
disposables,
755762
);
763+
watcher.register();
756764

757765
await watcher.startLanguageServer(languageServer, Uri.parse('folder1'));
758766
await watcher.startLanguageServer(languageServer, Uri.parse('folder2'));
@@ -832,6 +840,7 @@ suite('Language server watcher', () => {
832840
{} as LspNotebooksExperiment,
833841
disposables,
834842
);
843+
watcher.register();
835844

836845
await watcher.startLanguageServer(languageServer, Uri.parse('workspace1'));
837846
await watcher.startLanguageServer(languageServer, Uri.parse('workspace2'));
@@ -920,6 +929,7 @@ suite('Language server watcher', () => {
920929
{} as LspNotebooksExperiment,
921930
disposables,
922931
);
932+
watcher.register();
923933

924934
const startLanguageServerSpy = sandbox.spy(watcher, 'startLanguageServer');
925935

@@ -1000,6 +1010,7 @@ suite('Language server watcher', () => {
10001010
{} as LspNotebooksExperiment,
10011011
disposables,
10021012
);
1013+
watcher.register();
10031014

10041015
const startLanguageServerSpy = sandbox.spy(watcher, 'startLanguageServer');
10051016

@@ -1083,6 +1094,7 @@ suite('Language server watcher', () => {
10831094
{} as LspNotebooksExperiment,
10841095
disposables,
10851096
);
1097+
watcher.register();
10861098

10871099
const startLanguageServerSpy = sandbox.spy(watcher, 'startLanguageServer');
10881100

@@ -1166,6 +1178,7 @@ suite('Language server watcher', () => {
11661178
{} as LspNotebooksExperiment,
11671179
disposables,
11681180
);
1181+
watcher.register();
11691182

11701183
const startLanguageServerSpy = sandbox.spy(watcher, 'startLanguageServer');
11711184

0 commit comments

Comments
 (0)