Skip to content

Commit 596e70e

Browse files
author
Kartik Raj
committed
Only activate interpreter and language server component when in a virtual workspace
1 parent cebb407 commit 596e70e

File tree

7 files changed

+66
-57
lines changed

7 files changed

+66
-57
lines changed

src/client/activation/activationManager.ts

+19-13
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { IFileSystem } from '../common/platform/types';
1313
import { IDisposable, IExperimentService, IInterpreterPathService, Resource } from '../common/types';
1414
import { Deferred } from '../common/utils/async';
1515
import { IInterpreterAutoSelectionService } from '../interpreter/autoSelection/types';
16+
import { IInterpreterActivationService, IInterpreterSingleActivationService } from '../interpreter/contracts';
1617
import { traceDecoratorError } from '../logging';
1718
import { sendActivationTelemetry } from '../telemetry/envFileTelemetry';
1819
import {
@@ -45,6 +46,10 @@ export class ExtensionActivationManager implements IExtensionActivationManager {
4546
@inject(IExperimentService) private readonly experiments: IExperimentService,
4647
@inject(IInterpreterPathService) private readonly interpreterPathService: IInterpreterPathService,
4748
@inject(ILanguageServerActivation) private readonly languageServerActivation: ILanguageServerActivation,
49+
@multiInject(IInterpreterActivationService)
50+
private readonly interpreterActivationServices: IInterpreterActivationService[],
51+
@multiInject(IInterpreterSingleActivationService)
52+
private readonly interpreterSingleActivationServices: IInterpreterSingleActivationService[],
4853
) {}
4954

5055
public dispose(): void {
@@ -63,14 +68,14 @@ export class ExtensionActivationManager implements IExtensionActivationManager {
6368

6469
// Activate all activation services together.
6570

66-
if (this.workspaceService.isVirtualWorkspace) {
67-
await this.activateWorkspace(this.activeResourceService.getActiveResource());
68-
} else {
69-
await Promise.all([
70-
...this.singleActivationServices.map((item) => item.activate()),
71-
this.activateWorkspace(this.activeResourceService.getActiveResource()),
72-
]);
73-
}
71+
const singleActivationServices = this.workspaceService.isVirtualWorkspace
72+
? this.interpreterSingleActivationServices
73+
: this.singleActivationServices;
74+
75+
await Promise.all([
76+
...singleActivationServices.map((item) => item.activate()),
77+
this.activateWorkspace(this.activeResourceService.getActiveResource()),
78+
]);
7479
}
7580

7681
@traceDecoratorError('Failed to activate a workspace')
@@ -83,16 +88,17 @@ export class ExtensionActivationManager implements IExtensionActivationManager {
8388

8489
await sendActivationTelemetry(this.fileSystem, this.workspaceService, resource);
8590

91+
if (this.experiments.inExperimentSync(DeprecatePythonPath.experiment)) {
92+
await this.interpreterPathService.copyOldInterpreterStorageValuesToNew(resource);
93+
}
94+
await this.autoSelection.autoSelectInterpreter(resource);
8695
if (this.workspaceService.isVirtualWorkspace) {
8796
await this.languageServerActivation.activate(resource);
97+
await Promise.all(this.interpreterActivationServices.map((item) => item.activate(resource)));
8898
} else {
89-
if (this.experiments.inExperimentSync(DeprecatePythonPath.experiment)) {
90-
await this.interpreterPathService.copyOldInterpreterStorageValuesToNew(resource);
91-
}
92-
await this.autoSelection.autoSelectInterpreter(resource);
9399
await Promise.all(this.activationServices.map((item) => item.activate(resource)));
94-
await this.appDiagnostics.performPreStartupHealthCheck(resource);
95100
}
101+
await this.appDiagnostics.performPreStartupHealthCheck(resource);
96102
}
97103

98104
public async initialize(): Promise<void> {

src/client/activation/activationService.ts

+5-9
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export class LanguageServerExtensionActivationService
5555

5656
private readonly output: OutputChannel;
5757

58-
private readonly interpreterService?: IInterpreterService;
58+
private readonly interpreterService: IInterpreterService;
5959

6060
private readonly languageServerChangeHandler: LanguageServerChangeHandler;
6161

@@ -67,18 +67,14 @@ export class LanguageServerExtensionActivationService
6767
) {
6868
this.workspaceService = this.serviceContainer.get<IWorkspaceService>(IWorkspaceService);
6969
this.configurationService = this.serviceContainer.get<IConfigurationService>(IConfigurationService);
70-
if (!this.workspaceService.isVirtualWorkspace) {
71-
this.interpreterService = this.serviceContainer.get<IInterpreterService>(IInterpreterService);
72-
}
70+
this.interpreterService = this.serviceContainer.get<IInterpreterService>(IInterpreterService);
7371
this.output = this.serviceContainer.get<OutputChannel>(IOutputChannel, STANDARD_OUTPUT_CHANNEL);
7472

7573
const disposables = serviceContainer.get<IDisposableRegistry>(IDisposableRegistry);
7674
disposables.push(this);
7775
disposables.push(this.workspaceService.onDidChangeConfiguration(this.onDidChangeConfiguration.bind(this)));
7876
disposables.push(this.workspaceService.onDidChangeWorkspaceFolders(this.onWorkspaceFoldersChanged, this));
79-
if (this.interpreterService) {
80-
disposables.push(this.interpreterService.onDidChangeInterpreter(this.onDidChangeInterpreter.bind(this)));
81-
}
77+
disposables.push(this.interpreterService.onDidChangeInterpreter(this.onDidChangeInterpreter.bind(this)));
8278

8379
this.languageServerChangeHandler = new LanguageServerChangeHandler(
8480
this.getCurrentLanguageServerType(),
@@ -95,7 +91,7 @@ export class LanguageServerExtensionActivationService
9591
const stopWatch = new StopWatch();
9692
// Get a new server and dispose of the old one (might be the same one)
9793
this.resource = resource;
98-
const interpreter = await this.interpreterService?.getActiveInterpreter(resource);
94+
const interpreter = await this.interpreterService.getActiveInterpreter(resource);
9995
const key = await this.getKey(resource, interpreter);
10096

10197
// If we have an old server with a different key, then deactivate it as the
@@ -307,7 +303,7 @@ export class LanguageServerExtensionActivationService
307303
resource,
308304
workspacePathNameForGlobalWorkspaces,
309305
);
310-
interpreter = interpreter || (await this.interpreterService?.getActiveInterpreter(resource));
306+
interpreter = interpreter || (await this.interpreterService.getActiveInterpreter(resource));
311307
const interperterPortion = interpreter ? `${interpreter.path}-${interpreter.envName}` : '';
312308
return `${resourcePortion}-${interperterPortion}`;
313309
}

src/client/extension.ts

+9-18
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ import { sendErrorTelemetry, sendStartupTelemetry } from './startupTelemetry';
4242
import { IStartupDurations } from './types';
4343
import { runAfterActivation } from './common/utils/runAfterActivation';
4444
import { IInterpreterService } from './interpreter/contracts';
45-
import { WorkspaceService } from './common/application/workspace';
4645

4746
durations.codeLoadingTime = stopWatch.elapsedTime;
4847

@@ -70,12 +69,9 @@ export async function activate(context: IExtensionContext): Promise<IExtensionAp
7069
// Send the "success" telemetry only if activation did not fail.
7170
// Otherwise Telemetry is send via the error handler.
7271

73-
const workspace = new WorkspaceService();
74-
if (!workspace.isVirtualWorkspace) {
75-
sendStartupTelemetry(ready, durations, stopWatch, serviceContainer)
76-
// Run in the background.
77-
.ignoreErrors();
78-
}
72+
sendStartupTelemetry(ready, durations, stopWatch, serviceContainer)
73+
// Run in the background.
74+
.ignoreErrors();
7975
return api;
8076
}
8177

@@ -137,13 +133,11 @@ async function activateUnsafe(
137133
setTimeout(async () => {
138134
if (activatedServiceContainer) {
139135
const workspaceService = activatedServiceContainer.get<IWorkspaceService>(IWorkspaceService);
140-
if (!workspaceService.isVirtualWorkspace) {
141-
const interpreterManager = activatedServiceContainer.get<IInterpreterService>(IInterpreterService);
142-
const workspaces = workspaceService.workspaceFolders ?? [];
143-
await interpreterManager
144-
.refresh(workspaces.length > 0 ? workspaces[0].uri : undefined)
145-
.catch((ex) => traceError('Python Extension: interpreterManager.refresh', ex));
146-
}
136+
const interpreterManager = activatedServiceContainer.get<IInterpreterService>(IInterpreterService);
137+
const workspaces = workspaceService.workspaceFolders ?? [];
138+
await interpreterManager
139+
.refresh(workspaces.length > 0 ? workspaces[0].uri : undefined)
140+
.catch((ex) => traceError('Python Extension: interpreterManager.refresh', ex));
147141
}
148142

149143
runAfterActivation();
@@ -167,10 +161,7 @@ async function handleError(ex: Error, startupDurations: IStartupDurations) {
167161
);
168162
traceError('extension activation failed', ex);
169163

170-
const workspace = new WorkspaceService();
171-
if (!workspace.isVirtualWorkspace) {
172-
await sendErrorTelemetry(ex, startupDurations, activatedServiceContainer);
173-
}
164+
await sendErrorTelemetry(ex, startupDurations, activatedServiceContainer);
174165
}
175166

176167
interface IAppShell {

src/client/extensionActivation.ts

+4-11
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,6 @@ export async function activateComponents(
7070
// https://github.com/microsoft/vscode-python/issues/15380
7171
// These will go away eventually once everything is refactored into components.
7272
const legacyActivationResult = await activateLegacy(ext);
73-
const workspaceService = ext.legacyIOC.serviceContainer.get<IWorkspaceService>(IWorkspaceService);
74-
if (workspaceService.isVirtualWorkspace) {
75-
// Nothing other than Pylance is activated when using virtual workspaces.
76-
return [legacyActivationResult];
77-
}
7873
const promises: Promise<ActivationResult>[] = [
7974
// More component activations will go here
8075
pythonEnvironments.activate(components.pythonEnvs, ext),
@@ -122,8 +117,9 @@ async function activateLegacy(ext: ExtensionState): Promise<ActivationResult> {
122117
// directly queries VSCode API.
123118
setLoggingLevel(getLoggingLevel());
124119

125-
// `IConfigurationService` may depend any of the registered types, so doing it after all registrations are finished.
126120
const configuration = serviceManager.get<IConfigurationService>(IConfigurationService);
121+
// Settings are dependent on Experiment service, so we need to initialize it after experiments are activated.
122+
serviceContainer.get<IConfigurationService>(IConfigurationService).getSettings().initialize();
127123
const languageServerType = configuration.getSettings().languageServer;
128124

129125
// Language feature registrations.
@@ -137,12 +133,12 @@ async function activateLegacy(ext: ExtensionState): Promise<ActivationResult> {
137133
const workspaceService = serviceContainer.get<IWorkspaceService>(IWorkspaceService);
138134
const cmdManager = serviceContainer.get<ICommandManager>(ICommandManager);
139135
languages.setLanguageConfiguration(PYTHON_LANGUAGE, getLanguageConfiguration());
136+
const interpreterManager = serviceContainer.get<IInterpreterService>(IInterpreterService);
137+
interpreterManager.initialize();
140138
if (!workspaceService.isVirtualWorkspace) {
141139
const handlers = serviceManager.getAll<IDebugSessionEventHandlers>(IDebugSessionEventHandlers);
142140
const dispatcher = new DebugSessionEventDispatcher(handlers, DebugService.instance, disposables);
143141
dispatcher.registerEventHandlers();
144-
const interpreterManager = serviceContainer.get<IInterpreterService>(IInterpreterService);
145-
interpreterManager.initialize();
146142

147143
const outputChannel = serviceManager.get<OutputChannel>(IOutputChannel, STANDARD_OUTPUT_CHANNEL);
148144
disposables.push(cmdManager.registerCommand(Commands.ViewOutput, () => outputChannel.show()));
@@ -194,9 +190,6 @@ async function activateLegacy(ext: ExtensionState): Promise<ActivationResult> {
194190
const manager = serviceContainer.get<IExtensionActivationManager>(IExtensionActivationManager);
195191
context.subscriptions.push(manager);
196192

197-
// Settings are dependent on Experiment service, so we need to initialize it after experiments are activated.
198-
serviceContainer.get<IConfigurationService>(IConfigurationService).getSettings().initialize();
199-
200193
const activationPromise = manager.activate();
201194

202195
return { fullyReady: activationPromise };

src/client/interpreter/contracts.ts

+7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { SemVer } from 'semver';
22
import { CodeLensProvider, ConfigurationTarget, Disposable, Event, TextDocument, Uri } from 'vscode';
3+
import { IExtensionActivationService, IExtensionSingleActivationService } from '../activation/types';
34
import { FileChangeType } from '../common/platform/fileSystemWatcher';
45
import { Resource } from '../common/types';
56
import { PythonEnvSource } from '../pythonEnvironments/base/info';
@@ -14,6 +15,12 @@ export type PythonEnvironmentsChangedEvent = {
1415
new?: PythonEnvironment | undefined;
1516
};
1617

18+
export const IInterpreterActivationService = Symbol('IInterpreterActivationService');
19+
export interface IInterpreterActivationService extends IExtensionActivationService {}
20+
21+
export const IInterpreterSingleActivationService = Symbol('IInterpreterSingleActivationService');
22+
export interface IInterpreterSingleActivationService extends IExtensionSingleActivationService {}
23+
1724
export const IComponentAdapter = Symbol('IComponentAdapter');
1825
export interface IComponentAdapter {
1926
readonly onRefreshStart: Event<void>;

src/client/interpreter/serviceRegistry.ts

+22-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,14 @@ import {
2323
IPythonPathUpdaterServiceFactory,
2424
IPythonPathUpdaterServiceManager,
2525
} from './configuration/types';
26-
import { IInterpreterDisplay, IInterpreterHelper, IInterpreterService, IShebangCodeLensProvider } from './contracts';
26+
import {
27+
IInterpreterSingleActivationService,
28+
IInterpreterDisplay,
29+
IInterpreterHelper,
30+
IInterpreterService,
31+
IShebangCodeLensProvider,
32+
IInterpreterActivationService,
33+
} from './contracts';
2734
import { InterpreterDisplay } from './display';
2835
import { InterpreterLocatorProgressStatubarHandler } from './display/progressDisplay';
2936
import { ShebangCodeLensProvider } from './display/shebangCodeLensProvider';
@@ -52,8 +59,21 @@ export function registerInterpreterTypes(serviceManager: IServiceManager): void
5259
IExtensionSingleActivationService,
5360
SetShebangInterpreterCommand,
5461
);
62+
serviceManager.addSingleton<IInterpreterSingleActivationService>(
63+
IInterpreterSingleActivationService,
64+
SetInterpreterCommand,
65+
);
66+
serviceManager.addSingleton<IInterpreterSingleActivationService>(
67+
IInterpreterSingleActivationService,
68+
ResetInterpreterCommand,
69+
);
70+
serviceManager.addSingleton<IInterpreterSingleActivationService>(
71+
IInterpreterSingleActivationService,
72+
SetShebangInterpreterCommand,
73+
);
5574

5675
serviceManager.addSingleton<IExtensionActivationService>(IExtensionActivationService, VirtualEnvironmentPrompt);
76+
serviceManager.addSingleton<IInterpreterActivationService>(IInterpreterActivationService, VirtualEnvironmentPrompt);
5777

5878
serviceManager.addSingleton<IInterpreterService>(IInterpreterService, InterpreterService);
5979
serviceManager.addSingleton<IInterpreterDisplay>(IInterpreterDisplay, InterpreterDisplay);
@@ -84,6 +104,7 @@ export function registerInterpreterTypes(serviceManager: IServiceManager): void
84104
);
85105

86106
serviceManager.addSingleton<IExtensionActivationService>(IExtensionActivationService, CondaInheritEnvPrompt);
107+
serviceManager.addSingleton<IInterpreterActivationService>(IInterpreterActivationService, CondaInheritEnvPrompt);
87108
}
88109

89110
export function registerTypes(serviceManager: IServiceManager): void {

src/client/jupyter/jupyterIntegration.ts

-5
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import { dirname } from 'path';
99
import { CancellationToken, Disposable, Event, Extension, Memento, Uri } from 'vscode';
1010
import * as lsp from 'vscode-languageserver-protocol';
1111
import { ILanguageServerCache, ILanguageServerConnection } from '../activation/types';
12-
import { IWorkspaceService } from '../common/application/types';
1312
import { JUPYTER_EXTENSION_ID } from '../common/constants';
1413
import { InterpreterUri, ModuleInstallFlags } from '../common/installer/types';
1514
import {
@@ -177,14 +176,10 @@ export class JupyterExtensionIntegration {
177176
@inject(IMemento) @named(GLOBAL_MEMENTO) private globalState: Memento,
178177
@inject(IInterpreterDisplay) private interpreterDisplay: IInterpreterDisplay,
179178
@inject(IComponentAdapter) private pyenvs: IComponentAdapter,
180-
@inject(IWorkspaceService) private workspace: IWorkspaceService,
181179
) {}
182180

183181
public registerApi(jupyterExtensionApi: JupyterExtensionApi): JupyterExtensionApi | undefined {
184182
// Forward python parts
185-
if (this.workspace.isVirtualWorkspace) {
186-
return undefined;
187-
}
188183
jupyterExtensionApi.registerPythonApi({
189184
onDidChangeInterpreter: this.interpreterService.onDidChangeInterpreter,
190185
getActiveInterpreter: async (resource?: Uri) => this.interpreterService.getActiveInterpreter(resource),

0 commit comments

Comments
 (0)