Skip to content

Commit 2179b30

Browse files
karthiknadigKartik Rajkimadelinejakebailey
authored
Cherry picks from main to release (#15421)
* Do not call activate the discovery component before registering all the classes (#15379) * Do not attempt to activate discovery component before registering all the classes * Add clarification comment * Code reviews * Skip windows store and shims paths when using known path locators (#15388) * Skip windows store and shims paths when using known path locators * Clean up and comments * Tests * Handle cases where envs variables might not be set * Typo Co-authored-by: Kim-Adeline Miguel <[email protected]> Co-authored-by: Kim-Adeline Miguel <[email protected]> * Change "Pylance not installed" prompt to allow reverting to Jedi (#15420) * Allow on suggestion refresh by default (#15430) Co-authored-by: Kartik Raj <[email protected]> Co-authored-by: Kim-Adeline Miguel <[email protected]> Co-authored-by: Jake Bailey <[email protected]>
1 parent 5553953 commit 2179b30

19 files changed

+332
-75
lines changed

package.nls.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,11 @@
4949
"Pylance.proposePylanceMessage": "Try out a new faster, feature-rich language server for Python by Microsoft, Pylance! Install the extension now.",
5050
"Pylance.tryItNow": "Try it now",
5151
"Pylance.remindMeLater": "Remind me later",
52-
"Pylance.installPylanceMessage": "Pylance extension is not installed. Click Yes to open Pylance installation page.",
5352
"Pylance.pylanceNotInstalledMessage": "Pylance extension is not installed.",
5453
"Pylance.pylanceInstalledReloadPromptMessage": "Pylance extension is now installed. Reload window to activate?",
54+
"Pylance.pylanceRevertToJediPrompt": "The Pylance extension is not installed but the python.languageServer value is set to \"Pylance\". Would you like to install the Pylance extension to use Pylance, or revert back to Jedi?",
55+
"Pylance.pylanceInstallPylance": "Install Pylance",
56+
"Pylance.pylanceRevertToJedi": "Revert to Jedi",
5557
"Experiments.inGroup": "User belongs to experiment group '{0}'",
5658
"Experiments.optedOutOf": "User opted out of experiment group '{0}'",
5759
"Interpreters.RefreshingInterpreters": "Refreshing Python Interpreters",

package.nls.ru.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
"Pylance.proposePylanceMessage": "Попробуйте новый языковый сервер для Python от Microsoft: Pylance! Установите расширение Pylance.",
3535
"Pylance.tryItNow": "Да, хочу",
3636
"Pylance.remindMeLater": "Напомните позже",
37-
"Pylance.installPylanceMessage": "Расширение Pylance не установлено. Нажмите Да чтобы открыть страницу установки Pylance.",
3837
"Pylance.pylanceNotInstalledMessage": "Расширение Pylance не установлено.",
3938
"Pylance.pylanceInstalledReloadPromptMessage": "Расширение Pylance установлено. Перезагрузить окно для его активации?",
4039
"LanguageService.reloadAfterLanguageServerChange": "Пожалуйста, перезагрузите окно после смены типа языкового сервера."

package.nls.zh-cn.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
"Pylance.proposePylanceMessage": "试试微软新的更快的、功能丰富的语言服务器 Pylance! ",
5050
"Pylance.tryItNow": "立即安装",
5151
"Pylance.remindMeLater": "稍后提醒",
52-
"Pylance.installPylanceMessage": "Pylance 扩展未安装。点击 \"\" 打开 Pylance 安装页面。",
5352
"Pylance.pylanceNotInstalledMessage": "Pylance 扩展未安装。",
5453
"Pylance.pylanceInstalledReloadPromptMessage": "Pylance 扩展未安装。重新加载窗口以激活?",
5554
"Experiments.inGroup": "用户属于 '{0}' 实验组",

src/client/activation/activationService.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ export class LanguageServerExtensionActivationService
8686
this.serviceContainer.get<IExtensions>(IExtensions),
8787
this.serviceContainer.get<IApplicationShell>(IApplicationShell),
8888
this.serviceContainer.get<ICommandManager>(ICommandManager),
89+
this.serviceContainer.get<IWorkspaceService>(IWorkspaceService),
90+
this.serviceContainer.get<IConfigurationService>(IConfigurationService),
8991
);
9092
disposables.push(this.languageServerChangeHandler);
9193
}

src/client/activation/common/activatorBase.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export abstract class LanguageServerActivatorBase implements ILanguageServerActi
4242
protected resource?: Resource;
4343
constructor(
4444
protected readonly manager: ILanguageServerManager,
45-
private readonly workspace: IWorkspaceService,
45+
protected readonly workspace: IWorkspaceService,
4646
protected readonly fs: IFileSystem,
4747
protected readonly configurationService: IConfigurationService,
4848
) {}

src/client/activation/common/languageServerChangeHandler.ts

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,43 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4-
import { Disposable } from 'vscode';
5-
import { IApplicationShell, ICommandManager } from '../../common/application/types';
4+
import { ConfigurationTarget, Disposable } from 'vscode';
5+
import { IApplicationShell, ICommandManager, IWorkspaceService } from '../../common/application/types';
66
import { PYLANCE_EXTENSION_ID } from '../../common/constants';
7-
import { IExtensions } from '../../common/types';
7+
import { IConfigurationService, IExtensions } from '../../common/types';
88
import { createDeferred } from '../../common/utils/async';
99
import { Common, LanguageService, Pylance } from '../../common/utils/localize';
1010
import { LanguageServerType } from '../types';
1111

1212
export async function promptForPylanceInstall(
1313
appShell: IApplicationShell,
1414
commandManager: ICommandManager,
15+
workspace: IWorkspaceService,
16+
configService: IConfigurationService,
1517
): Promise<void> {
16-
// If not installed, point user to Pylance at the store.
1718
const response = await appShell.showWarningMessage(
18-
Pylance.installPylanceMessage(),
19-
Common.bannerLabelYes(),
20-
Common.bannerLabelNo(),
19+
Pylance.pylanceRevertToJediPrompt(),
20+
Pylance.pylanceInstallPylance(),
21+
Pylance.pylanceRevertToJedi(),
22+
Pylance.remindMeLater(),
2123
);
2224

23-
if (response === Common.bannerLabelYes()) {
25+
if (response === Pylance.pylanceInstallPylance()) {
2426
commandManager.executeCommand('extension.open', PYLANCE_EXTENSION_ID);
27+
} else if (response === Pylance.pylanceRevertToJedi()) {
28+
const inspection = workspace.getConfiguration('python').inspect<string>('languageServer');
29+
30+
let target: ConfigurationTarget | undefined;
31+
if (inspection?.workspaceValue) {
32+
target = ConfigurationTarget.Workspace;
33+
} else if (inspection?.globalValue) {
34+
target = ConfigurationTarget.Global;
35+
}
36+
37+
if (target) {
38+
await configService.updateSetting('languageServer', LanguageServerType.Jedi, undefined, target);
39+
commandManager.executeCommand('workbench.action.reloadWindow');
40+
}
2541
}
2642
}
2743

@@ -37,6 +53,8 @@ export class LanguageServerChangeHandler implements Disposable {
3753
private readonly extensions: IExtensions,
3854
private readonly appShell: IApplicationShell,
3955
private readonly commands: ICommandManager,
56+
private readonly workspace: IWorkspaceService,
57+
private readonly configService: IConfigurationService,
4058
) {
4159
this.pylanceInstalled = this.isPylanceInstalled();
4260
this.disposables.push(
@@ -70,7 +88,7 @@ export class LanguageServerChangeHandler implements Disposable {
7088
let response: string | undefined;
7189
if (lsType === LanguageServerType.Node && !this.isPylanceInstalled()) {
7290
// If not installed, point user to Pylance at the store.
73-
await promptForPylanceInstall(this.appShell, this.commands);
91+
await promptForPylanceInstall(this.appShell, this.commands, this.workspace, this.configService);
7492
// At this point Pylance is not yet installed. Skip reload prompt
7593
// since we are going to show it when Pylance becomes available.
7694
} else {

src/client/activation/node/activator.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,12 @@ export class NodeLanguageServerActivator extends LanguageServerActivatorBase {
4747
// Pylance is not yet installed. Throw will cause activator to use Jedi
4848
// temporarily. Language server installation tracker will prompt for window
4949
// reload when Pylance becomes available.
50-
await promptForPylanceInstall(this.appShell, this.commandManager);
50+
await promptForPylanceInstall(
51+
this.appShell,
52+
this.commandManager,
53+
this.workspace,
54+
this.configurationService,
55+
);
5156
throw new Error(Pylance.pylanceNotInstalledMessage());
5257
}
5358
}

src/client/common/utils/localize.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,6 @@ export namespace Pylance {
114114
export const tryItNow = localize('Pylance.tryItNow', 'Try it now');
115115
export const remindMeLater = localize('Pylance.remindMeLater', 'Remind me later');
116116

117-
export const installPylanceMessage = localize(
118-
'Pylance.installPylanceMessage',
119-
'Pylance extension is not installed. Click Yes to open Pylance installation page.',
120-
);
121117
export const pylanceNotInstalledMessage = localize(
122118
'Pylance.pylanceNotInstalledMessage',
123119
'Pylance extension is not installed.',
@@ -126,6 +122,13 @@ export namespace Pylance {
126122
'Pylance.pylanceInstalledReloadPromptMessage',
127123
'Pylance extension is now installed. Reload window to activate?',
128124
);
125+
126+
export const pylanceRevertToJediPrompt = localize(
127+
'Pylance.pylanceRevertToJediPrompt',
128+
'The Pylance extension is not installed but the python.languageServer value is set to "Pylance". Would you like to install the Pylance extension to use Pylance, or revert back to Jedi?',
129+
);
130+
export const pylanceInstallPylance = localize('Pylance.pylanceInstallPylance', 'Install Pylance');
131+
export const pylanceRevertToJedi = localize('Pylance.pylanceRevertToJedi', 'Revert to Jedi');
129132
}
130133

131134
export namespace Jupyter {

src/client/extensionActivation.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,19 @@ export async function activateComponents(
7878
// `Promise.all()`, etc.) will flatten nested promises. Thus
7979
// activation resolves `ActivationResult`, which can safely wrap
8080
// the "inner" promise.
81+
82+
// TODO: As of now activateLegacy() registers various classes which might
83+
// be required while activating components. Once registration from
84+
// activateLegacy() are moved before we activate other components, we can
85+
// activate them parallelly with the other components.
86+
// https://github.com/microsoft/vscode-python/issues/15380
87+
// These will go away eventually once everything is refactored into components.
88+
const legacyActivationResult = await activateLegacy(ext);
8189
const promises: Promise<ActivationResult>[] = [
90+
// More component activations will go here
8291
pythonEnvironments.activate(components.pythonEnvs),
83-
// These will go away eventually.
84-
activateLegacy(ext),
8592
];
86-
return Promise.all(promises);
93+
return Promise.all([legacyActivationResult, ...promises]);
8794
}
8895

8996
/// //////////////////////////

src/client/pythonEnvironments/base/locators/lowLevel/windowsKnownPathsLocator.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import { Event } from 'vscode';
99
import { getSearchPathEntries } from '../../../../common/utils/exec';
1010
import { Disposables, IDisposable } from '../../../../common/utils/resourceLifecycle';
1111
import { isStandardPythonBinary } from '../../../common/commonUtils';
12+
import { isPyenvShimDir } from '../../../discovery/locators/services/pyenvLocator';
13+
import { isWindowsStoreDir } from '../../../discovery/locators/services/windowsStoreLocator';
1214
import { PythonEnvInfo, PythonEnvKind, PythonEnvSource } from '../../info';
1315
import { ILocator, IPythonEnvsIterator, PythonLocatorQuery } from '../../locator';
1416
import { Locators } from '../../locators';
@@ -31,6 +33,17 @@ export class WindowsPathEnvVarLocator implements ILocator, IDisposable {
3133

3234
constructor() {
3335
const dirLocators: (ILocator & IDisposable)[] = getSearchPathEntries()
36+
.filter((dirname) => {
37+
// Filter out following directories:
38+
// 1. Windows Store app directories: We have a store app locator that handles this. The
39+
// python.exe available in these directories might not be python. It can be a store
40+
// install shortcut that takes you to windows store.
41+
//
42+
// 2. Filter out pyenv shims: They are not actual python binaries, they are used to launch
43+
// the binaries specified in .python-version file in the cwd. We should not be reporting
44+
// those binaries as environments.
45+
return !isWindowsStoreDir(dirname) && !isPyenvShimDir(dirname);
46+
})
3447
// Build a locator for each directory.
3548
.map((dirname) => getDirFilesLocator(dirname, PythonEnvKind.Unknown));
3649
this.disposables.push(...dirLocators);

0 commit comments

Comments
 (0)