Skip to content

Commit be48f1d

Browse files
committed
1 parent 8349236 commit be48f1d

5 files changed

Lines changed: 51 additions & 28 deletions

File tree

src/vs/platform/extensionManagement/common/extensionManagement.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
1010
import { URI } from 'vs/base/common/uri';
1111
import { CancellationToken } from 'vs/base/common/cancellation';
1212
import { IExtensionManifest, IExtension, ExtensionType } from 'vs/platform/extensions/common/extensions';
13-
import { IExeBasedExtensionTip } from 'vs/platform/product/common/productService';
1413

1514
export const EXTENSION_IDENTIFIER_PATTERN = '^([a-z0-9A-Z][a-z0-9-A-Z]*)\\.([a-z0-9A-Z][a-z0-9-A-Z]*)$';
1615
export const EXTENSION_IDENTIFIER_REGEX = new RegExp(EXTENSION_IDENTIFIER_PATTERN);
@@ -235,7 +234,14 @@ export type IConfigBasedExtensionTip = {
235234
readonly configName: string,
236235
readonly important: boolean,
237236
};
238-
export type IExecutableBasedExtensionTip = { extensionId: string } & Omit<Omit<IExeBasedExtensionTip, 'recommendations'>, 'important'>;
237+
238+
export type IExecutableBasedExtensionTip = {
239+
readonly extensionId: string,
240+
readonly friendlyName: string,
241+
readonly exeFriendlyName: string,
242+
readonly windowsPath?: string,
243+
};
244+
239245
export type IWorkspaceTips = { readonly remoteSet: string[]; readonly recommendations: string[]; };
240246

241247
export const IExtensionTipsService = createDecorator<IExtensionTipsService>('IExtensionTipsService');

src/vs/platform/extensionManagement/node/extensionTipsService.ts

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,31 @@
55

66
import { URI } from 'vs/base/common/uri';
77
import { join, } from 'vs/base/common/path';
8-
import { IProductService, IExeBasedExtensionTip } from 'vs/platform/product/common/productService';
8+
import { IProductService } from 'vs/platform/product/common/productService';
99
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
1010
import { env as processEnv } from 'vs/base/common/process';
1111
import { INativeEnvironmentService } from 'vs/platform/environment/node/environmentService';
1212
import { IFileService } from 'vs/platform/files/common/files';
1313
import { isWindows } from 'vs/base/common/platform';
1414
import { isNonEmptyArray } from 'vs/base/common/arrays';
1515
import { IExecutableBasedExtensionTip } from 'vs/platform/extensionManagement/common/extensionManagement';
16-
import { IStringDictionary, forEach } from 'vs/base/common/collections';
16+
import { forEach } from 'vs/base/common/collections';
1717
import { IRequestService } from 'vs/platform/request/common/request';
1818
import { ILogService } from 'vs/platform/log/common/log';
1919
import { ExtensionTipsService as BaseExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionTipsService';
2020

21+
type IExeBasedExtensionTips = {
22+
readonly exeFriendlyName: string,
23+
readonly windowsPath?: string,
24+
readonly recommendations: { extensionId: string, extensionName: string }[];
25+
};
26+
2127
export class ExtensionTipsService extends BaseExtensionTipsService {
2228

2329
_serviceBrand: any;
2430

25-
private readonly allImportantExecutableTips: IStringDictionary<IExeBasedExtensionTip> = {};
26-
private readonly allOtherExecutableTips: IStringDictionary<IExeBasedExtensionTip> = {};
31+
private readonly allImportantExecutableTips: Map<string, IExeBasedExtensionTips> = new Map<string, IExeBasedExtensionTips>();
32+
private readonly allOtherExecutableTips: Map<string, IExeBasedExtensionTips> = new Map<string, IExeBasedExtensionTips>();
2733

2834
constructor(
2935
@IEnvironmentService private readonly environmentService: INativeEnvironmentService,
@@ -35,10 +41,20 @@ export class ExtensionTipsService extends BaseExtensionTipsService {
3541
super(fileService, productService, requestService, logService);
3642
if (productService.exeBasedExtensionTips) {
3743
forEach(productService.exeBasedExtensionTips, ({ key, value }) => {
38-
if (value.important) {
39-
this.allImportantExecutableTips[key] = value;
40-
} else {
41-
this.allOtherExecutableTips[key] = value;
44+
const importantRecommendations: { extensionId: string, extensionName: string }[] = [];
45+
const otherRecommendations: { extensionId: string, extensionName: string }[] = [];
46+
forEach(value.recommendations, ({ key: extensionId, value }) => {
47+
if (value.important) {
48+
importantRecommendations.push({ extensionId, extensionName: value.name });
49+
} else {
50+
otherRecommendations.push({ extensionId, extensionName: value.name });
51+
}
52+
});
53+
if (importantRecommendations.length) {
54+
this.allImportantExecutableTips.set(key, { exeFriendlyName: value.friendlyName, windowsPath: value.windowsPath, recommendations: importantRecommendations });
55+
}
56+
if (otherRecommendations.length) {
57+
this.allOtherExecutableTips.set(key, { exeFriendlyName: value.friendlyName, windowsPath: value.windowsPath, recommendations: otherRecommendations });
4258
}
4359
});
4460
}
@@ -52,13 +68,13 @@ export class ExtensionTipsService extends BaseExtensionTipsService {
5268
return this.getValidExecutableBasedExtensionTips(this.allOtherExecutableTips);
5369
}
5470

55-
private async getValidExecutableBasedExtensionTips(executableTips: IStringDictionary<IExeBasedExtensionTip>): Promise<IExecutableBasedExtensionTip[]> {
71+
private async getValidExecutableBasedExtensionTips(executableTips: Map<string, IExeBasedExtensionTips>): Promise<IExecutableBasedExtensionTip[]> {
5672
const result: IExecutableBasedExtensionTip[] = [];
5773

5874
const checkedExecutables: Map<string, boolean> = new Map<string, boolean>();
59-
for (const exeName of Object.keys(executableTips)) {
60-
const extensionTip = executableTips[exeName];
61-
if (!isNonEmptyArray(extensionTip?.recommendations)) {
75+
for (const exeName of executableTips.keys()) {
76+
const extensionTip = executableTips.get(exeName);
77+
if (!extensionTip || !isNonEmptyArray(extensionTip.recommendations)) {
6278
continue;
6379
}
6480

@@ -83,12 +99,14 @@ export class ExtensionTipsService extends BaseExtensionTipsService {
8399
checkedExecutables.set(exePath, exists);
84100
}
85101
if (exists) {
86-
extensionTip.recommendations.forEach(recommendation => result.push({
87-
extensionId: recommendation,
88-
friendlyName: extensionTip.friendlyName,
89-
exeFriendlyName: extensionTip.exeFriendlyName,
90-
windowsPath: extensionTip.windowsPath,
91-
}));
102+
for (const { extensionId, extensionName: friendlyName } of extensionTip.recommendations) {
103+
result.push({
104+
extensionId,
105+
friendlyName,
106+
exeFriendlyName: extensionTip.exeFriendlyName,
107+
windowsPath: extensionTip.windowsPath,
108+
});
109+
}
92110
}
93111
}
94112
}

src/vs/platform/product/common/productService.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,7 @@ export interface IConfigBasedExtensionTip {
131131
export interface IExeBasedExtensionTip {
132132
friendlyName: string;
133133
windowsPath?: string;
134-
recommendations: readonly string[];
135-
important?: boolean;
136-
exeFriendlyName?: string;
134+
recommendations: IStringDictionary<{ name: string, important?: boolean }>;
137135
}
138136

139137
export interface IRemoteExtensionTip {

src/vs/workbench/contrib/extensions/browser/exeBasedRecommendations.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,11 @@ export class ExeBasedRecommendations extends ExtensionRecommendations {
8585
return;
8686
}
8787

88-
const extensionId = recommendations[0];
89-
const tip = importantExeBasedRecommendations[extensionId];
90-
const message = localize('exeRecommended', "The '{0}' extension is recommended as you have {1} installed on your system.", tip.friendlyName!, tip.exeFriendlyName || basename(tip.windowsPath!));
91-
this.promptImportantExtensionInstallNotification(extensionId, message);
88+
for (const extensionId of recommendations) {
89+
const tip = importantExeBasedRecommendations[extensionId];
90+
const message = localize('exeRecommended', "The '{0}' extension is recommended as you have {1} installed on your system.", tip.friendlyName!, tip.exeFriendlyName || basename(tip.windowsPath!));
91+
this.promptImportantExtensionInstallNotification(extensionId, message);
92+
}
9293
}
9394

9495
private groupByInstalled(recommendationsToSuggest: string[], local: ILocalExtension[]): { installed: string[], uninstalled: string[] } {

src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ export class TerminalConfigHelper implements IBrowserTerminalConfigHelper {
294294
if (!exeBasedExtensionTips || !exeBasedExtensionTips.wsl) {
295295
return;
296296
}
297-
const extId = exeBasedExtensionTips.wsl.recommendations[0];
297+
const extId = Object.keys(exeBasedExtensionTips.wsl.recommendations).find(extId => exeBasedExtensionTips.wsl.recommendations[extId].important);
298298
if (extId && ! await this.isExtensionInstalled(extId)) {
299299
this._notificationService.prompt(
300300
Severity.Info,

0 commit comments

Comments
 (0)