diff --git a/src/vs/platform/configuration/common/configuration.ts b/src/vs/platform/configuration/common/configuration.ts index f68f3ca029330394bf08f01eda4921fd7bd16b31..1b36f95daee7afbdb3dea76c7b3e9b7cbea30ee9 100644 --- a/src/vs/platform/configuration/common/configuration.ts +++ b/src/vs/platform/configuration/common/configuration.ts @@ -5,6 +5,7 @@ import {createDecorator, ServiceIdentifier} from 'vs/platform/instantiation/common/instantiation'; import {IEventEmitter} from 'vs/base/common/eventEmitter'; +import Event from 'vs/base/common/event'; import winjs = require('vs/base/common/winjs.base'); export var IConfigurationService = createDecorator('configurationService'); @@ -21,7 +22,12 @@ export interface IConfigurationService extends IEventEmitter { /** * Returns iff the workspace has configuration or not. */ - hasWorkspaceConfiguration():boolean; + hasWorkspaceConfiguration(): boolean; + + /** + * Event that fires when the configuration changes. + */ + onDidUpdateConfiguration: Event<{ config: any }> } export class ConfigurationServiceEventTypes { diff --git a/src/vs/platform/configuration/common/configurationService.ts b/src/vs/platform/configuration/common/configurationService.ts index 56c335597199af951d0bf780590f04899ee6ed9b..4bb95d3448d9ecee1871c4f9bf0111a73966b1d3 100644 --- a/src/vs/platform/configuration/common/configurationService.ts +++ b/src/vs/platform/configuration/common/configurationService.ts @@ -19,6 +19,7 @@ import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; import Files = require('vs/platform/files/common/files'); import {IConfigurationRegistry, Extensions} from './configurationRegistry'; import {Registry} from 'vs/platform/platform'; +import Event, {fromEventEmitter} from 'vs/base/common/event'; // ---- service abstract implementation @@ -43,6 +44,8 @@ interface ILoadConfigResult { export abstract class ConfigurationService extends eventEmitter.EventEmitter implements IConfigurationService, lifecycle.IDisposable { public serviceId = IConfigurationService; + public onDidUpdateConfiguration: Event<{ config: any }>; + protected contextService: IWorkspaceContextService; protected eventService: IEventService; protected workspaceSettingsRootFolder: string; @@ -67,6 +70,8 @@ export abstract class ConfigurationService extends eventEmitter.EventEmitter imp unbind(); subscription.dispose(); } + + this.onDidUpdateConfiguration = fromEventEmitter(this, ConfigurationServiceEventTypes.UPDATED); } protected abstract resolveContents(resource: uri[]): winjs.TPromise; @@ -229,6 +234,10 @@ export class NullConfigurationService extends eventEmitter.EventEmitter implemen public hasWorkspaceConfiguration(): boolean { return false; } + + public onDidUpdateConfiguration() { + return { dispose() { } }; + } } export var nullService = new NullConfigurationService(); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts index ac4d2128b60b81ad82000bcf2e11ae771ad3a44f..4e5462dd69e64b946e62adff22f8a3779827b938 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts @@ -75,7 +75,7 @@ export class ExtensionTipsService implements IExtensionTipsService { private _onDidChangeTips: Emitter = new Emitter(); private _tips: { [id: string]: ExtensionTip } = Object.create(null); - private _toDispose: IDisposable[] = []; + private _disposeOnUpdate: IDisposable[] = []; private _availableExtensions: Promise; private _extensionData: Promise; @@ -83,18 +83,13 @@ export class ExtensionTipsService implements IExtensionTipsService { @IExtensionsService private _extensionService: IExtensionsService, @IGalleryService private _galleryService: IGalleryService, @IModelService private _modelService: IModelService, - @IConfigurationService configurationService: IConfigurationService + @IConfigurationService private _configurationService: IConfigurationService ) { - - configurationService.loadConfiguration('extensions').then(value => { - if (value && value.experimentalSuggestions === true) { - this._init(); - } - }, onUnexpectedError); + this._updateState(); } dispose() { - this._toDispose = disposeAll(this._toDispose); + this._disposeOnUpdate = disposeAll(this._disposeOnUpdate); } get onDidChangeTips(): Event { @@ -107,7 +102,26 @@ export class ExtensionTipsService implements IExtensionTipsService { return tips.map(tip => tip.extension); } - private _init() { + // --- internals + + private _updateState(): void { + + // check with configuration service and then GO + this._disposeOnUpdate = disposeAll(this._disposeOnUpdate); + this._tips = Object.create(null); + this._onDidChangeTips.fire(this.tips); + + this._configurationService.loadConfiguration('extensions').then(value => { + if (value && value.showTips === true) { + this._init(); + } + }, onUnexpectedError); + + // listen for config changes + this._configurationService.onDidUpdateConfiguration(this._updateState, this, this._disposeOnUpdate); + } + + private _init():void { if (!this._galleryService.isEnabled()) { return; @@ -122,7 +136,7 @@ export class ExtensionTipsService implements IExtensionTipsService { this._availableExtensions = this._getAvailableExtensions(); // don't suggest what got installed - this._toDispose.push(this._extensionService.onDidInstallExtension(ext => { + this._disposeOnUpdate.push(this._extensionService.onDidInstallExtension(ext => { const id = `${ext.publisher}.${ext.name}`; let change = false; if (delete this._tips[id]) { @@ -139,16 +153,16 @@ export class ExtensionTipsService implements IExtensionTipsService { // such that files you type have bigger impact on the suggest // order than those you only look at const modelListener: { [uri: string]: IDisposable } = Object.create(null); - this._toDispose.push({ dispose() { disposeAll(values(modelListener)) } }); + this._disposeOnUpdate.push({ dispose() { disposeAll(values(modelListener)) } }); - this._toDispose.push(this._modelService.onModelAdded(model => { + this._disposeOnUpdate.push(this._modelService.onModelAdded(model => { const uri = model.getAssociatedResource(); this._suggestByResource(uri, ExtensionTipReasons.FileOpened); modelListener[uri.toString()] = model.addListener2(EventType.ModelContentChanged2, () => this._suggestByResource(uri, ExtensionTipReasons.FileEdited)); })); - this._toDispose.push(this._modelService.onModelRemoved(model => { + this._disposeOnUpdate.push(this._modelService.onModelRemoved(model => { const subscription = modelListener[model.getAssociatedResource().toString()]; if (subscription) { subscription.dispose(); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts index b5072bd315e47674b68d13a908bb645e0dfe00b9..7f897041b17e871aa70affaae24840faff8dc3a3 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import nls = require('vs/nls'); import platform = require('vs/platform/platform'); import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import statusbar = require('vs/workbench/browser/parts/statusbar/statusbar'); @@ -11,6 +12,7 @@ import { IGalleryService } from 'vs/workbench/parts/extensions/common/extensions import { GalleryService } from 'vs/workbench/parts/extensions/node/vsoGalleryService'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { ExtensionsWorkbenchExtension } from 'vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchExtension'; +import ConfigurationRegistry = require('vs/platform/configuration/common/configurationRegistry'); // Register Gallery Service registerSingleton(IGalleryService, GalleryService); @@ -32,4 +34,17 @@ registerSingleton(IGalleryService, GalleryService); ExtensionTipsStatusbarItem, statusbar.StatusbarAlignment.LEFT, 9 /* Low Priority */ -)); \ No newline at end of file +)); + + +(platform.Registry.as(ConfigurationRegistry.Extensions.Configuration)).registerConfiguration({ + id: 'extensions', + type: 'object', + properties: { + 'extensions.showTips': { + type: 'boolean', + default: false, + description: nls.localize('extConfig', "Suggest extensions based on changed and open files."), + } + } +}); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsWidgets.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsWidgets.ts index 1461cf9046acd239113124eea7d479de7566a66a..7fec6debf3295df5ca8a2a292d86c599f278e25b 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsWidgets.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsWidgets.ts @@ -97,6 +97,12 @@ export class ExtensionTipsStatusbarItem implements statusbar.IStatusbarItem { ) { this._extensionTipsService.onDidChangeTips(tips => { + + if (tips.length === 0) { + dom.removeClass(this._domNode, 'active'); + return; + } + // check for new tips let hasNewTips = false; for (let tip of tips) { diff --git a/src/vs/workbench/test/browser/servicesTestUtils.ts b/src/vs/workbench/test/browser/servicesTestUtils.ts index 730f8373df11ee582f485c233913a3ee8c6fbac3..2f7455b1103a79ebf377f319e8228baedc85bc83 100644 --- a/src/vs/workbench/test/browser/servicesTestUtils.ts +++ b/src/vs/workbench/test/browser/servicesTestUtils.ts @@ -514,4 +514,8 @@ export class TestConfigurationService extends EventEmitter.EventEmitter implemen public hasWorkspaceConfiguration():boolean { return false; } + + public onDidUpdateConfiguration() { + return { dispose() { } }; + } } \ No newline at end of file