Skip to content

Commit 4e20c2b

Browse files
authored
Fixes to the LS no reload work (#18984)
* Delete refCountedLanguageServer.ts * Stop LS is workspace folder removed * Only one LS for Pylance and None * Dispose LS in multiroot scenario only with Jedi
1 parent fa8d1e7 commit 4e20c2b

File tree

6 files changed

+257
-199
lines changed

6 files changed

+257
-199
lines changed

.eslintignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,6 @@ src/client/activation/commands.ts
174174
src/client/activation/progress.ts
175175
src/client/activation/extensionSurvey.ts
176176
src/client/activation/common/analysisOptions.ts
177-
src/client/activation/refCountedLanguageServer.ts
178177
src/client/activation/languageClientMiddleware.ts
179178

180179
src/client/formatters/serviceRegistry.ts

package.nls.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,9 +175,9 @@
175175
"LanguageService.extractionCompletedOutputMessage": "Language server download complete",
176176
"LanguageService.extractionDoneOutputMessage": "done",
177177
"LanguageService.reloadVSCodeIfSeachPathHasChanged": "Search paths have changed for this Python interpreter. Please reload the extension to ensure that the IntelliSense works correctly",
178-
"LanguageService.startingPylance": "Starting Pylance language server for {0}.",
178+
"LanguageService.startingPylance": "Starting Pylance language server.",
179179
"LanguageService.startingJedi": "Starting Jedi language server for {0}.",
180-
"LanguageService.startingNone": "Editor support is inactive since language server is set to None for {0}.",
180+
"LanguageService.startingNone": "Editor support is inactive since language server is set to None.",
181181
"LanguageService.reloadAfterLanguageServerChange": "Please reload the window switching between language servers.",
182182
"AttachProcess.unsupportedOS": "Operating system '{0}' not supported.",
183183
"AttachProcess.attachTitle": "Attach to process",

src/client/activation/refCountedLanguageServer.ts

Lines changed: 0 additions & 126 deletions
This file was deleted.

src/client/common/utils/localize.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -213,14 +213,11 @@ export namespace LanguageService {
213213
text: localize('LanguageService.statusItem.text', 'Partial Mode'),
214214
detail: localize('LanguageService.statusItem.detail', 'Limited IntelliSense provided by Pylance'),
215215
};
216-
export const startingPylance = localize(
217-
'LanguageService.startingPylance',
218-
'Starting Pylance language server for {0}.',
219-
);
216+
export const startingPylance = localize('LanguageService.startingPylance', 'Starting Pylance language server.');
220217
export const startingJedi = localize('LanguageService.startingJedi', 'Starting Jedi language server for {0}.');
221218
export const startingNone = localize(
222219
'LanguageService.startingNone',
223-
'Editor support is inactive since language server is set to None for {0}.',
220+
'Editor support is inactive since language server is set to None.',
224221
);
225222
export const untrustedWorkspaceMessage = localize(
226223
'LanguageService.untrustedWorkspaceMessage',

src/client/languageServer/watcher.ts

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import * as path from 'path';
55
import { inject, injectable } from 'inversify';
6-
import { ConfigurationChangeEvent, Uri } from 'vscode';
6+
import { ConfigurationChangeEvent, Uri, WorkspaceFoldersChangeEvent } from 'vscode';
77
import { LanguageServerChangeHandler } from '../activation/common/languageServerChangeHandler';
88
import {
99
IExtensionActivationService,
@@ -50,7 +50,9 @@ export class LanguageServerWatcher
5050

5151
private workspaceInterpreters: Map<string, PythonEnvironment | undefined>;
5252

53-
// In a multiroot workspace scenario we will have one language server per folder.
53+
// In a multiroot workspace scenario we may have multiple language servers running:
54+
// When using Jedi, there will be one language server per workspace folder.
55+
// When using Pylance, there will only be one language server for the project.
5456
private workspaceLanguageServers: Map<string, ILanguageServerExtensionManager | undefined>;
5557

5658
private languageServerChangeHandler: LanguageServerChangeHandler;
@@ -77,6 +79,10 @@ export class LanguageServerWatcher
7779

7880
disposables.push(this.workspaceService.onDidChangeConfiguration(this.onDidChangeConfiguration.bind(this)));
7981

82+
disposables.push(
83+
this.workspaceService.onDidChangeWorkspaceFolders(this.onDidChangeWorkspaceFolders.bind(this)),
84+
);
85+
8086
if (this.workspaceService.isTrusted) {
8187
disposables.push(this.interpreterPathService.onDidChange(this.onDidChangeInterpreter.bind(this)));
8288
}
@@ -113,7 +119,7 @@ export class LanguageServerWatcher
113119
languageServerType: LanguageServerType,
114120
resource?: Resource,
115121
): Promise<ILanguageServerExtensionManager> {
116-
const lsResource = this.getWorkspaceKey(resource);
122+
const lsResource = this.getWorkspaceUri(resource);
117123
const currentInterpreter = this.workspaceInterpreters.get(lsResource.fsPath);
118124
const interpreter = await this.interpreterService?.getActiveInterpreter(resource);
119125

@@ -142,6 +148,15 @@ export class LanguageServerWatcher
142148
serverType = LanguageServerType.None;
143149
}
144150

151+
// If the language server type is Pylance or None,
152+
// We only need to instantiate the language server once, even in multiroot workspace scenarios,
153+
// so we only need one language server extension manager.
154+
const key = this.getWorkspaceKey(resource, serverType);
155+
const languageServer = this.workspaceLanguageServers.get(key);
156+
if ((serverType === LanguageServerType.Node || serverType === LanguageServerType.None) && languageServer) {
157+
return languageServer;
158+
}
159+
145160
// Instantiate the language server extension manager.
146161
const languageServerExtensionManager = this.createLanguageServer(serverType);
147162

@@ -156,16 +171,16 @@ export class LanguageServerWatcher
156171
await languageServerExtensionManager.languageServerNotAvailable();
157172
}
158173

159-
this.workspaceLanguageServers.set(lsResource.fsPath, languageServerExtensionManager);
174+
this.workspaceLanguageServers.set(key, languageServerExtensionManager);
160175

161176
return languageServerExtensionManager;
162177
}
163178

164179
// ILanguageServerCache
165180

166181
public async get(resource?: Resource): Promise<ILanguageServer> {
167-
const lsResource = this.getWorkspaceKey(resource);
168-
let languageServerExtensionManager = this.workspaceLanguageServers.get(lsResource.fsPath);
182+
const key = this.getWorkspaceKey(resource, this.languageServerType);
183+
let languageServerExtensionManager = this.workspaceLanguageServers.get(key);
169184

170185
if (!languageServerExtensionManager) {
171186
languageServerExtensionManager = await this.startAndGetLanguageServer(this.languageServerType, resource);
@@ -177,13 +192,13 @@ export class LanguageServerWatcher
177192
// Private methods
178193

179194
private stopLanguageServer(resource?: Resource): void {
180-
const lsResource = this.getWorkspaceKey(resource);
181-
const languageServerExtensionManager = this.workspaceLanguageServers.get(lsResource.fsPath);
195+
const key = this.getWorkspaceKey(resource, this.languageServerType);
196+
const languageServerExtensionManager = this.workspaceLanguageServers.get(key);
182197

183198
if (languageServerExtensionManager) {
184199
languageServerExtensionManager.stopLanguageServer();
185200
languageServerExtensionManager.dispose();
186-
this.workspaceLanguageServers.delete(lsResource.fsPath);
201+
this.workspaceLanguageServers.delete(key);
187202
}
188203
}
189204

@@ -228,11 +243,11 @@ export class LanguageServerWatcher
228243
}
229244

230245
private async refreshLanguageServer(resource?: Resource): Promise<void> {
231-
const lsResource = this.getWorkspaceKey(resource);
246+
const lsResource = this.getWorkspaceUri(resource);
232247
const languageServerType = this.configurationService.getSettings(lsResource).languageServer;
233248

234249
if (languageServerType !== this.languageServerType) {
235-
this.stopLanguageServer(lsResource);
250+
this.stopLanguageServer(resource);
236251
await this.startLanguageServer(languageServerType, lsResource);
237252
}
238253
}
@@ -267,8 +282,19 @@ export class LanguageServerWatcher
267282
}
268283
}
269284

270-
// Get the workspace key for the given resource, in order to query this.workspaceInterpreters and this.workspaceLanguageServers.
271-
private getWorkspaceKey(resource?: Resource): Uri {
285+
// Watch for workspace folder changes.
286+
private async onDidChangeWorkspaceFolders(event: WorkspaceFoldersChangeEvent): Promise<void> {
287+
// Since Jedi is the only language server type where we instantiate multiple language servers,
288+
// Make sure to dispose of them only in that scenario.
289+
if (event.removed.length && this.languageServerType === LanguageServerType.Jedi) {
290+
event.removed.forEach((workspace) => {
291+
this.stopLanguageServer(workspace.uri);
292+
});
293+
}
294+
}
295+
296+
// Get the workspace Uri for the given resource, in order to query this.workspaceInterpreters and this.workspaceLanguageServers.
297+
private getWorkspaceUri(resource?: Resource): Uri {
272298
let uri;
273299

274300
if (resource) {
@@ -279,6 +305,19 @@ export class LanguageServerWatcher
279305

280306
return uri ?? Uri.parse('default');
281307
}
308+
309+
// Get the key used to identify which language server extension manager is associated to which workspace.
310+
// When using Pylance or having no LS enabled, we return a static key since there should only be one LS extension manager for these LS types.
311+
private getWorkspaceKey(resource: Resource | undefined, languageServerType: LanguageServerType): string {
312+
switch (languageServerType) {
313+
case LanguageServerType.Node:
314+
return 'Pylance';
315+
case LanguageServerType.None:
316+
return 'None';
317+
default:
318+
return this.getWorkspaceUri(resource).fsPath;
319+
}
320+
}
282321
}
283322

284323
function logStartup(languageServerType: LanguageServerType, resource: Uri): void {
@@ -290,10 +329,10 @@ function logStartup(languageServerType: LanguageServerType, resource: Uri): void
290329
outputLine = LanguageService.startingJedi().format(basename);
291330
break;
292331
case LanguageServerType.Node:
293-
outputLine = LanguageService.startingPylance().format(basename);
332+
outputLine = LanguageService.startingPylance();
294333
break;
295334
case LanguageServerType.None:
296-
outputLine = LanguageService.startingNone().format(basename);
335+
outputLine = LanguageService.startingNone();
297336
break;
298337
default:
299338
throw new Error(`Unknown language server type: ${languageServerType}`);

0 commit comments

Comments
 (0)