diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index fabf4aee66e3ad4a03a4b186656580c47cb8d3fb..60e4f5af93aae529e68050a7bec96ebb14415448 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -285,7 +285,7 @@ export const IExtensionTipsService = createDecorator('ext export interface IExtensionTipsService { _serviceBrand: any; getRecommendations(): string[]; - getWorkspaceRecommendations(): string[]; + getWorkspaceRecommendations(): TPromise; } export const ExtensionsLabel = localize('extensions', "Extensions"); diff --git a/src/vs/workbench/parts/extensions/browser/extensionTipsService.ts b/src/vs/workbench/parts/extensions/browser/extensionTipsService.ts index ec14e2e4e0e176e147f2bbdeb5d31b2ef07980a0..c951649b9d4c2d35e2e03d995a16d4805b5c2b59 100644 --- a/src/vs/workbench/parts/extensions/browser/extensionTipsService.ts +++ b/src/vs/workbench/parts/extensions/browser/extensionTipsService.ts @@ -4,11 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; +import * as paths from 'vs/base/common/paths'; +import { TPromise } from 'vs/base/common/winjs.base'; import { forEach } from 'vs/base/common/collections'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { match } from 'vs/base/common/glob'; +import * as json from 'vs/base/common/json'; import { IExtensionManagementService, IExtensionGalleryService, IExtensionTipsService, LocalExtensionType, EXTENSION_IDENTIFIER_PATTERN } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { IExtensionsConfiguration, ConfigurationKey } from 'vs/workbench/parts/extensions/common/extensions'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IModel } from 'vs/editor/common/editorCommon'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; @@ -17,8 +19,13 @@ import { IChoiceService } from 'vs/platform/message/common/message'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ShowRecommendedExtensionsAction, ShowWorkspaceRecommendedExtensionsAction } from 'vs/workbench/parts/extensions/browser/extensionsActions'; import Severity from 'vs/base/common/severity'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { Schemas } from 'vs/base/common/network'; +import { IFileService } from 'vs/platform/files/common/files'; + +interface IExtensionsContent { + recommendations: string[]; +} export class ExtensionTipsService implements IExtensionTipsService { @@ -37,7 +44,8 @@ export class ExtensionTipsService implements IExtensionTipsService { @IChoiceService private choiceService: IChoiceService, @IExtensionManagementService private extensionsService: IExtensionManagementService, @IInstantiationService private instantiationService: IInstantiationService, - @IConfigurationService private configurationService: IConfigurationService + @IFileService private fileService: IFileService, + @IWorkspaceContextService private contextService: IWorkspaceContextService ) { if (!this._galleryService.isEnabled()) { return; @@ -47,15 +55,17 @@ export class ExtensionTipsService implements IExtensionTipsService { this._suggestWorkspaceRecommendations(); } - getWorkspaceRecommendations(): string[] { - const configuration = this.configurationService.getConfiguration(ConfigurationKey); - if (configuration.recommendations) { - const regEx = new RegExp(EXTENSION_IDENTIFIER_PATTERN); - return configuration.recommendations.filter((element, position) => { - return configuration.recommendations.indexOf(element) === position && regEx.test(element); - }); - } - return configuration.recommendations || []; + getWorkspaceRecommendations(): TPromise { + return this.fileService.resolveContent(this.contextService.toResource(paths.join('.vscode', 'extensions.json'))).then(content => { + const extensionsContent = json.parse(content.value, []); + if (extensionsContent.recommendations) { + const regEx = new RegExp(EXTENSION_IDENTIFIER_PATTERN); + return extensionsContent.recommendations.filter((element, position) => { + return extensionsContent.recommendations.indexOf(element) === position && regEx.test(element); + }); + } + return []; + }, err => []); } getRecommendations(): string[] { @@ -166,36 +176,37 @@ export class ExtensionTipsService implements IExtensionTipsService { return; } - const allRecommendations = this.getWorkspaceRecommendations(); - - if (!allRecommendations.length) { - return; - } - - this.extensionsService.getInstalled(LocalExtensionType.User).done(local => { - const recommendations = allRecommendations - .filter(id => local.every(local => `${local.manifest.publisher}.${local.manifest.name}` !== id)); - - if (!recommendations.length) { + this.getWorkspaceRecommendations().done(allRecommendations => { + if (!allRecommendations.length) { return; } - const message = localize('workspaceRecommended', "This workspace has extension recommendations."); - const action = this.instantiationService.createInstance(ShowWorkspaceRecommendedExtensionsAction, ShowWorkspaceRecommendedExtensionsAction.ID, localize('showRecommendations', "Show Recommendations")); - - const options = [ - action.label, - localize('neverShowAgain', "Don't show again"), - localize('close', "Close") - ]; + this.extensionsService.getInstalled(LocalExtensionType.User).done(local => { + const recommendations = allRecommendations + .filter(id => local.every(local => `${local.manifest.publisher}.${local.manifest.name}` !== id)); - this.choiceService.choose(Severity.Info, message, options).done(choice => { - switch (choice) { - case 0: return action.run(); - case 1: return this.storageService.store(storageKey, true, StorageScope.WORKSPACE); + if (!recommendations.length) { + return; } + + const message = localize('workspaceRecommended', "This workspace has extension recommendations."); + const action = this.instantiationService.createInstance(ShowWorkspaceRecommendedExtensionsAction, ShowWorkspaceRecommendedExtensionsAction.ID, localize('showRecommendations', "Show Recommendations")); + + const options = [ + action.label, + localize('neverShowAgain', "Don't show again"), + localize('close', "Close") + ]; + + this.choiceService.choose(Severity.Info, message, options).done(choice => { + switch (choice) { + case 0: return action.run(); + case 1: return this.storageService.store(storageKey, true, StorageScope.WORKSPACE); + } + }); }); }); + } dispose() { diff --git a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts index 43178cb117a736047c777a743edab62cbf9a1200..b9460ee942faf0e336444dd0866a27fda86fa182 100644 --- a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts @@ -15,7 +15,7 @@ import Event from 'vs/base/common/event'; import { ActionItem, IActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewlet, ConfigurationKey } from 'vs/workbench/parts/extensions/common/extensions'; +import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewlet } from 'vs/workbench/parts/extensions/common/extensions'; import { ExtensionsConfigurationInitialContent } from 'vs/workbench/parts/extensions/common/extensionsFileTemplate'; import { LocalExtensionType, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -1092,7 +1092,7 @@ export class ConfigureWorkspaceRecommendedExtensionsAction extends Action { } private getOrCreateExtensionsFile(): TPromise<{ created: boolean, extensionsFileResource: URI }> { - const extensionsFileResource = URI.file(paths.join(this.contextService.getWorkspace().resource.fsPath, '.vscode', `${ConfigurationKey}.json`)); + const extensionsFileResource = URI.file(paths.join(this.contextService.getWorkspace().resource.fsPath, '.vscode', 'extensions.json')); return this.fileService.resolveContent(extensionsFileResource).then(content => { return { created: false, extensionsFileResource }; diff --git a/src/vs/workbench/parts/extensions/common/extensions.ts b/src/vs/workbench/parts/extensions/common/extensions.ts index 756bf88db54b942e75b9f768d40719aadfa67f07..1bf876d07a617d4a2d5c9b6832fa462fe2f1e926 100644 --- a/src/vs/workbench/parts/extensions/common/extensions.ts +++ b/src/vs/workbench/parts/extensions/common/extensions.ts @@ -81,5 +81,4 @@ export const ConfigurationKey = 'extensions'; export interface IExtensionsConfiguration { autoUpdate: boolean; - recommendations: string[]; } \ No newline at end of file diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index aed14a81b8b524e7bba206e5b65963afcfa4e3c9..1b0329f95424cbbae7ff2b9389596febdd333b8e 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -302,17 +302,18 @@ export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet { private getWorkspaceRecommendationsModel(query: Query, options: IQueryOptions): TPromise> { const value = query.value.replace(/@recommended:workspace/g, '').trim().toLowerCase(); - const names = this.tipsService.getWorkspaceRecommendations() - .filter(name => name.toLowerCase().indexOf(value) > -1); + return this.tipsService.getWorkspaceRecommendations() + .then(recommendations => { + const names = recommendations.filter(name => name.toLowerCase().indexOf(value) > -1); + this.telemetryService.publicLog('extensionWorkspaceRecommendations:open', { count: names.length }); - this.telemetryService.publicLog('extensionWorkspaceRecommendations:open', { count: names.length }); - - if (!names.length) { - return TPromise.as(new PagedModel([])); - } + if (!names.length) { + return TPromise.as(new PagedModel([])); + } - return this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length })) - .then(result => new PagedModel(result)); + return this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length })) + .then(result => new PagedModel(result)); + }); } private openExtension(extension: IExtension): void { diff --git a/src/vs/workbench/services/configuration/common/configuration.ts b/src/vs/workbench/services/configuration/common/configuration.ts index ed2ae1d8d559ad22638e681ead03d2a208386d96..d8b03ca71544ebfa6ed10b2bb9dd6454f06eb451 100644 --- a/src/vs/workbench/services/configuration/common/configuration.ts +++ b/src/vs/workbench/services/configuration/common/configuration.ts @@ -40,8 +40,7 @@ export interface IWorkspaceConfigurationKeys extends IConfigurationKeys { export const WORKSPACE_STANDALONE_CONFIGURATIONS = { 'tasks': `${WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME}/tasks.json`, - 'launch': `${WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME}/launch.json`, - 'extensions': `${WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME}/extensions.json` + 'launch': `${WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME}/launch.json` }; export interface WorkspaceConfigurationNode {