Change:
Improve user experience while installing themes
!
It would be cool if you could preview themes in the store, maybe with a split view hosting some example code, or even with the files you have open.
Please open a feature request for it

Discussion:
import 'vs/css!./media/extensionActions'; import { localize } from 'vs/nls'; import { IAction, Action } from 'vs/base/common/actions'; <del> import { Throttler } from 'vs/base/common/async'; </del> <ins> import { Throttler, Delayer } from 'vs/base/common/async'; </ins> import * as DOM from 'vs/base/browser/dom'; import * as paths from 'vs/base/common/paths'; import { Event } from 'vs/base/common/event';

import { IExtensionService, IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; import { URI } from 'vs/base/common/uri'; import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; <del> import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; </del> <ins> import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; </ins> import { registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; import { buttonBackground, buttonForeground, buttonHoverBackground, contrastBorder, registerColor, foreground } from 'vs/platform/theme/common/colorRegistry'; import { Color } from 'vs/base/common/color';

import { IPartService } from 'vs/workbench/services/part/common/partService'; import { alert } from 'vs/base/browser/ui/aria/aria'; import { coalesce } from 'vs/base/common/arrays'; <ins> import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; </ins> function toExtensionDescription(local: ILocalExtension): IExtensionDescription { return {

@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @IInstantiationService private readonly instantiationService: IInstantiationService, @INotificationService private readonly notificationService: INotificationService, <del> @IOpenerService private readonly openerService: IOpenerService </del> <ins> @IOpenerService private readonly openerService: IOpenerService, @IQuickInputService private readonly quickInputService: IQuickInputService, @IExtensionService private readonly runtimeExtensionService: IExtensionService, @IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService </ins> ) { super(`extensions.install`, InstallAction.INSTALL_LABEL, InstallAction.Class, false); this.update();

} } <del> run(): Promise<any> { </del> <ins> async run(): Promise<any> { </ins> this.extensionsWorkbenchService.open(this.extension); alert(localize('installExtensionStart', "Installing extension {0} started. An editor is now open with more details on this extension", this.extension.displayName)); <del> return this.install(this.extension); </del> <ins> const extension = await this.install(this.extension); if (extension.local && extension.local.manifest.contributes && extension.local.manifest.contributes.themes && extension.local.manifest.contributes.themes.length) { return this.applyInstalledTheme(extension.local); } </ins> } <del> private install(extension: IExtension): Promise<any> { return this.extensionsWorkbenchService.install(extension).then(null, err => { if (!extension.gallery) { return this.notificationService.error(err); } </del> <ins> private install(extension: IExtension): Promise<IExtension> { return this.extensionsWorkbenchService.install(extension) .then(null, err => { if (!extension.gallery) { return this.notificationService.error(err); } </ins> <del> console.error(err); </del> <ins> console.error(err); </ins> <del> return promptDownloadManually(extension.gallery, localize('failedToInstall', "Failed to install '{0}'.", extension.identifier.id), err, this.instantiationService, this.notificationService, this.openerService); }); </del> <ins> return promptDownloadManually(extension.gallery, localize('failedToInstall', "Failed to install '{0}'.", extension.identifier.id), err, this.instantiationService, this.notificationService, this.openerService); }); } private async applyInstalledTheme(extension: ILocalExtension): Promise<void> { const runningExtension = await this.getRunningExtension(extension); if (runningExtension) { const currentTheme = this.workbenchThemeService.getColorTheme(); const themes = await this.workbenchThemeService.getColorThemes(runningExtension.identifier); const delayer = new Delayer<void>(100); const pickedTheme = await this.quickInputService.pick( themes.map(theme => (<IQuickPickItem>{ label: theme.label, id: theme.id })), { placeHolder: localize('apply installed theme', "Apply installed theme"), onDidFocus: item => delayer.trigger(() => this.workbenchThemeService.setColorTheme(item.id, ConfigurationTarget.MEMORY).then(() => undefined)) }); this.workbenchThemeService.setColorTheme(pickedTheme ? pickedTheme.id : currentTheme.id, undefined); } } private async getRunningExtension(extension: ILocalExtension): Promise<IExtensionDescription | null> { const runningExtension = await this.runtimeExtensionService.getExtension(extension.identifier.id); if (runningExtension) { return runningExtension; } if (this.runtimeExtensionService.canAddExtension(toExtensionDescription(extension))) { return new Promise<IExtensionDescription | null>((c, e) => { const disposable = this.runtimeExtensionService.onDidChangeExtensions(async () => { const runningExtension = await this.runtimeExtensionService.getExtension(extension.identifier.id); if (runningExtension) { disposable.dispose(); c(runningExtension); } }); }); } return null; </ins> } }

import { Color } from 'vs/base/common/color'; import { ITheme, IThemeService, IIconTheme } from 'vs/platform/theme/common/themeService'; import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; <ins> import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; </ins> export const IWorkbenchThemeService = createDecorator<IWorkbenchThemeService>('themeService');

_serviceBrand: any; setColorTheme(themeId: string | undefined, settingsTarget: ConfigurationTarget | undefined): Promise<IColorTheme | null>; getColorTheme(): IColorTheme; <del> getColorThemes(): Promise<IColorTheme[]>; </del> <ins> getColorThemes(extensionId?: ExtensionIdentifier): Promise<IColorTheme[]>; </ins> onDidColorThemeChange: Event<IColorTheme>; restoreColorTheme();

import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { textmateColorsSchemaId, registerColorThemeSchemas, textmateColorSettingsSchemaId } from 'vs/workbench/services/themes/common/colorThemeSchema'; import { workbenchColorsSchemaId } from 'vs/platform/theme/common/colorRegistry'; <ins> import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; </ins> // implementation

return this.currentColorTheme; } <del> public getColorThemes(): Promise<IColorTheme[]> { return this.colorThemeStore.getColorThemes(); </del> <ins> public async getColorThemes(extensionId?: ExtensionIdentifier): Promise<IColorTheme[]> { const colorThemes = await this.colorThemeStore.getColorThemes(); return extensionId ? colorThemes.filter(c => ExtensionIdentifier.equals(new ExtensionIdentifier(c.extensionData.extensionId), extensionId)) : colorThemes; </ins> } public getTheme(): ITheme {