55
66import { ExtensionRecommendationsService , milliSecondsInADay , choiceNever } from 'vs/workbench/contrib/extensions/browser/extensionRecommendationsService' ;
77import { IExtensionRecommendationsService , IWorkbenchExtensionEnablementService , ExtensionRecommendationReason , IExtensionRecommendation , ExtensionRecommendationSource } from 'vs/workbench/services/extensionManagement/common/extensionManagement' ;
8- import { URI } from 'vs/base/common/uri' ;
9- import { join , basename } from 'vs/base/common/path' ;
8+ import { basename } from 'vs/base/common/path' ;
109import { distinct , shuffle } from 'vs/base/common/arrays' ;
11- import { IExeBasedExtensionTip , IProductService } from 'vs/platform/product/common/productService' ;
12- import { IExtensionGalleryService , IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement' ;
10+ import { IProductService } from 'vs/platform/product/common/productService' ;
11+ import { IExtensionGalleryService , IExtensionManagementService , IExtensionTipsService , IExecutableBasedExtensionTip } from 'vs/platform/extensionManagement/common/extensionManagement' ;
1312import { IModelService } from 'vs/editor/common/services/modelService' ;
1413import { IStorageService , StorageScope } from 'vs/platform/storage/common/storage' ;
1514import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation' ;
@@ -31,10 +30,8 @@ import { ExtensionType } from 'vs/platform/extensions/common/extensions';
3130import { localize } from 'vs/nls' ;
3231import Severity from 'vs/base/common/severity' ;
3332import { InstallRecommendedExtensionAction , ShowRecommendedExtensionsAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions' ;
34- import { forEach } from 'vs/base/common/collections' ;
35- import { platform , env as processEnv } from 'vs/base/common/process' ;
33+ import { forEach , IStringDictionary } from 'vs/base/common/collections' ;
3634import { isNumber } from 'vs/base/common/types' ;
37- import { INativeEnvironmentService } from 'vs/platform/environment/node/environmentService' ;
3835
3936interface IDynamicWorkspaceRecommendations {
4037 remoteSet : string [ ] ;
@@ -43,8 +40,7 @@ interface IDynamicWorkspaceRecommendations {
4340
4441export class NativeExtensionRecommendationsService extends ExtensionRecommendationsService implements IExtensionRecommendationsService {
4542
46- private _exeBasedRecommendations : { [ id : string ] : IExeBasedExtensionTip ; } = Object . create ( null ) ;
47- private _importantExeBasedRecommendations : { [ id : string ] : IExeBasedExtensionTip ; } = Object . create ( null ) ;
43+ private _exeBasedRecommendations : { [ id : string ] : IExecutableBasedExtensionTip ; } = Object . create ( null ) ;
4844 private proactiveRecommendationsFetched : boolean = false ;
4945 private _extensionsRecommendationsUrl : string | undefined ;
5046 private _dynamicWorkspaceRecommendations : string [ ] = [ ] ;
@@ -71,6 +67,7 @@ export class NativeExtensionRecommendationsService extends ExtensionRecommendati
7167 @IProductService productService : IProductService ,
7268 @IRequestService private readonly requestService : IRequestService ,
7369 @IWorkspaceTagsService private readonly workspaceTagsService : IWorkspaceTagsService ,
70+ @IExtensionTipsService private readonly extensionTipsService : IExtensionTipsService ,
7471 ) {
7572 super ( galleryService , modelService , storageService , extensionsService , extensionEnablementService , instantiationService , fileService , contextService ,
7673 configurationService , telemetryService , environmentService , extensionService , viewletService , notificationService , extensionManagementService , extensionWorkbenchService ,
@@ -111,14 +108,15 @@ export class NativeExtensionRecommendationsService extends ExtensionRecommendati
111108 if ( ! this . proactiveRecommendationsFetched ) {
112109 this . proactiveRecommendationsFetched = true ;
113110 // Executable based recommendations carry out a lot of file stats, delay the resolution so that the startup is not affected
114- fetchPromise = timeout ( 10000 ) . then ( ( ) => Promise . all ( [ this . fetchDynamicWorkspaceRecommendations ( ) , this . fetchExecutableRecommendations ( false ) ] ) ) ;
111+ fetchPromise = timeout ( 10000 ) . then ( ( ) => Promise . all ( [ this . fetchDynamicWorkspaceRecommendations ( ) , this . fetchOtherExeBasedRecommendations ( ) ] ) ) ;
115112 }
116113 return fetchPromise ;
117114 }
118115
119116 private async fetchImportantExeBasedRecommendation ( ) : Promise < void > {
120- await this . fetchExecutableRecommendations ( true ) ;
121- await this . promptForImportantExeBasedExtension ( ) ;
117+ const importantExectuableBasedTips = await this . extensionTipsService . getImportantExecutableBasedTips ( ) ;
118+ importantExectuableBasedTips . forEach ( tip => this . _exeBasedRecommendations [ tip . extensionId . toLowerCase ( ) ] = tip ) ;
119+ await this . promptForImportantExeBasedExtension ( importantExectuableBasedTips ) ;
122120 }
123121
124122 /**
@@ -209,13 +207,16 @@ export class NativeExtensionRecommendationsService extends ExtensionRecommendati
209207 }
210208 }
211209
212- private async promptForImportantExeBasedExtension ( ) : Promise < boolean > {
210+ private async promptForImportantExeBasedExtension ( importantExectuableBasedTips : IExecutableBasedExtensionTip [ ] ) : Promise < boolean > {
213211
214- let recommendationsToSuggest = Object . keys ( this . _importantExeBasedRecommendations ) ;
212+ const importantExeBasedRecommendations : IStringDictionary < IExecutableBasedExtensionTip > = { } ;
213+ importantExectuableBasedTips . forEach ( tip => importantExeBasedRecommendations [ tip . extensionId . toLowerCase ( ) ] = tip ) ;
214+
215+ let recommendationsToSuggest = Object . keys ( importantExeBasedRecommendations ) ;
215216
216217 const installed = await this . extensionManagementService . getInstalled ( ExtensionType . User ) ;
217218 recommendationsToSuggest = this . filterInstalled ( recommendationsToSuggest , installed , ( extensionId ) => {
218- const tip = this . _importantExeBasedRecommendations [ extensionId ] ;
219+ const tip = importantExeBasedRecommendations [ extensionId ] ;
219220
220221 /* __GDPR__
221222 "exeExtensionRecommendations:alreadyInstalled" : {
@@ -232,7 +233,7 @@ export class NativeExtensionRecommendationsService extends ExtensionRecommendati
232233 }
233234
234235 for ( const extensionId of recommendationsToSuggest ) {
235- const tip = this . _importantExeBasedRecommendations [ extensionId ] ;
236+ const tip = importantExeBasedRecommendations [ extensionId ] ;
236237
237238 /* __GDPR__
238239 "exeExtensionRecommendations:notInstalled" : {
@@ -259,7 +260,7 @@ export class NativeExtensionRecommendationsService extends ExtensionRecommendati
259260 }
260261
261262 const extensionId = recommendationsToSuggest [ 0 ] ;
262- const tip = this . _importantExeBasedRecommendations [ extensionId ] ;
263+ const tip = importantExeBasedRecommendations [ extensionId ] ;
263264 const message = localize ( 'exeRecommended' , "The '{0}' extension is recommended as you have {1} installed on your system." , tip . friendlyName ! , tip . exeFriendlyName || basename ( tip . windowsPath ! ) ) ;
264265
265266 this . notificationService . prompt ( Severity . Info , message ,
@@ -332,59 +333,9 @@ export class NativeExtensionRecommendationsService extends ExtensionRecommendati
332333 return true ;
333334 }
334335
335- /**
336- * If user has any of the tools listed in this.productService.exeBasedExtensionTips, fetch corresponding recommendations
337- */
338- private async fetchExecutableRecommendations ( important : boolean ) : Promise < void > {
339- if ( ! this . productService . exeBasedExtensionTips ) {
340- return ;
341- }
342-
343- const foundExecutables : Set < string > = new Set < string > ( ) ;
344- const findExecutable = ( exeName : string , tip : IExeBasedExtensionTip , path : string ) => {
345- return this . fileService . exists ( URI . file ( path ) ) . then ( exists => {
346- if ( exists && ! foundExecutables . has ( exeName ) ) {
347- foundExecutables . add ( exeName ) ;
348- ( tip [ 'recommendations' ] || [ ] ) . forEach ( extensionId => {
349- if ( tip . friendlyName ) {
350- if ( important ) {
351- this . _importantExeBasedRecommendations [ extensionId . toLowerCase ( ) ] = tip ;
352- }
353- this . _exeBasedRecommendations [ extensionId . toLowerCase ( ) ] = tip ;
354- }
355- } ) ;
356- }
357- } ) ;
358- } ;
359-
360- const promises : Promise < void > [ ] = [ ] ;
361- // Loop through recommended extensions
362- forEach ( this . productService . exeBasedExtensionTips , entry => {
363- if ( typeof entry . value !== 'object' || ! Array . isArray ( entry . value [ 'recommendations' ] ) ) {
364- return ;
365- }
366- if ( important !== ! ! entry . value . important ) {
367- return ;
368- }
369- const exeName = entry . key ;
370- if ( platform === 'win32' ) {
371- let windowsPath = entry . value [ 'windowsPath' ] ;
372- if ( ! windowsPath || typeof windowsPath !== 'string' ) {
373- return ;
374- }
375- windowsPath = windowsPath . replace ( '%USERPROFILE%' , processEnv [ 'USERPROFILE' ] ! )
376- . replace ( '%ProgramFiles(x86)%' , processEnv [ 'ProgramFiles(x86)' ] ! )
377- . replace ( '%ProgramFiles%' , processEnv [ 'ProgramFiles' ] ! )
378- . replace ( '%APPDATA%' , processEnv [ 'APPDATA' ] ! )
379- . replace ( '%WINDIR%' , processEnv [ 'WINDIR' ] ! ) ;
380- promises . push ( findExecutable ( exeName , entry . value , windowsPath ) ) ;
381- } else {
382- promises . push ( findExecutable ( exeName , entry . value , join ( '/usr/local/bin' , exeName ) ) ) ;
383- promises . push ( findExecutable ( exeName , entry . value , join ( ( this . environmentService as INativeEnvironmentService ) . userHome . fsPath , exeName ) ) ) ;
384- }
385- } ) ;
386-
387- await Promise . all ( promises ) ;
336+ private async fetchOtherExeBasedRecommendations ( ) : Promise < void > {
337+ const otherExectuableBasedTips = await this . extensionTipsService . getOtherExecutableBasedTips ( ) ;
338+ otherExectuableBasedTips . forEach ( tip => this . _exeBasedRecommendations [ tip . extensionId . toLowerCase ( ) ] = tip ) ;
388339 }
389340
390341 getAllRecommendationsWithReason ( ) : { [ id : string ] : { reasonId : ExtensionRecommendationReason , reasonText : string } ; } {
0 commit comments