Skip to content

Commit 22078d3

Browse files
authored
Change "Pylance not installed" prompt to allow reverting to Jedi (#15420)
1 parent a2cefcc commit 22078d3

10 files changed

Lines changed: 174 additions & 48 deletions

File tree

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/test/activation/node/activator.unit.test.ts

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { PYLANCE_EXTENSION_ID } from '../../../client/common/constants';
1717
import { FileSystem } from '../../../client/common/platform/fileSystem';
1818
import { IFileSystem } from '../../../client/common/platform/types';
1919
import { IConfigurationService, IExtensions, IPythonSettings } from '../../../client/common/types';
20-
import { Common, Pylance } from '../../../client/common/utils/localize';
20+
import { Pylance } from '../../../client/common/utils/localize';
2121

2222
suite('Pylance Language Server - Activator', () => {
2323
let activator: NodeLanguageServerActivator;
@@ -92,20 +92,22 @@ suite('Pylance Language Server - Activator', () => {
9292
test('When Pylance is not installed activator should show install prompt ', async () => {
9393
when(
9494
appShell.showWarningMessage(
95-
Pylance.installPylanceMessage(),
96-
Common.bannerLabelYes(),
97-
Common.bannerLabelNo(),
95+
Pylance.pylanceRevertToJediPrompt(),
96+
Pylance.pylanceInstallPylance(),
97+
Pylance.pylanceRevertToJedi(),
98+
Pylance.remindMeLater(),
9899
),
99-
).thenReturn(Promise.resolve(Common.bannerLabelNo()));
100+
).thenReturn(Promise.resolve(Pylance.remindMeLater()));
100101

101102
try {
102103
await activator.start(undefined);
103104
} catch {}
104105
verify(
105106
appShell.showWarningMessage(
106-
Pylance.installPylanceMessage(),
107-
Common.bannerLabelYes(),
108-
Common.bannerLabelNo(),
107+
Pylance.pylanceRevertToJediPrompt(),
108+
Pylance.pylanceInstallPylance(),
109+
Pylance.pylanceRevertToJedi(),
110+
Pylance.remindMeLater(),
109111
),
110112
).once();
111113
verify(commandManager.executeCommand('extension.open', PYLANCE_EXTENSION_ID)).never();
@@ -114,11 +116,12 @@ suite('Pylance Language Server - Activator', () => {
114116
test('When Pylance is not installed activator should open Pylance install page if users clicks Yes', async () => {
115117
when(
116118
appShell.showWarningMessage(
117-
Pylance.installPylanceMessage(),
118-
Common.bannerLabelYes(),
119-
Common.bannerLabelNo(),
119+
Pylance.pylanceRevertToJediPrompt(),
120+
Pylance.pylanceInstallPylance(),
121+
Pylance.pylanceRevertToJedi(),
122+
Pylance.remindMeLater(),
120123
),
121-
).thenReturn(Promise.resolve(Common.bannerLabelYes()));
124+
).thenReturn(Promise.resolve(Pylance.pylanceInstallPylance()));
122125

123126
try {
124127
await activator.start(undefined);

0 commit comments

Comments
 (0)