/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import 'vs/css!./welcomePage'; import 'vs/workbench/contrib/welcome/page/browser/vs_code_welcome_page'; import { URI } from 'vs/base/common/uri'; import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; import * as arrays from 'vs/base/common/arrays'; import { WalkThroughInput } from 'vs/workbench/contrib/welcome/walkThrough/browser/walkThroughInput'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { onUnexpectedError, isPromiseCanceledError } from 'vs/base/common/errors'; import { IWindowOpenable } from 'vs/platform/windows/common/windows'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { localize } from 'vs/nls'; import { Action, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { Schemas } from 'vs/base/common/network'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { getInstalledExtensions, IExtensionStatus, onExtensionChanged, isKeymapExtension } from 'vs/workbench/contrib/extensions/common/extensionsUtils'; import { IExtensionManagementService, IExtensionGalleryService, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IWorkbenchExtensionEnablementService, EnablementState, IExtensionRecommendationsService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { ILifecycleService, StartupKind } from 'vs/platform/lifecycle/common/lifecycle'; import { Disposable } from 'vs/base/common/lifecycle'; import { splitName } from 'vs/base/common/labels'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { registerColor, focusBorder, textLinkForeground, textLinkActiveForeground, foreground, descriptionForeground, contrastBorder, activeContrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { getExtraColor } from 'vs/workbench/contrib/welcome/walkThrough/common/walkThroughUtils'; import { IExtensionsViewPaneContainer, IExtensionsWorkbenchService, VIEWLET_ID } from 'vs/workbench/contrib/extensions/common/extensions'; import { IEditorInputFactory, EditorInput } from 'vs/workbench/common/editor'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { TimeoutTimer } from 'vs/base/common/async'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { ILabelService } from 'vs/platform/label/common/label'; import { IFileService } from 'vs/platform/files/common/files'; import { ExtensionType } from 'vs/platform/extensions/common/extensions'; import { joinPath } from 'vs/base/common/resources'; import { IRecentlyOpened, isRecentWorkspace, IRecentWorkspace, IRecentFolder, isRecentFolder, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IProductService } from 'vs/platform/product/common/productService'; import { IEditorOptions } from 'vs/platform/editor/common/editor'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; const configurationKey = 'workbench.startupEditor'; const oldConfigurationKey = 'workbench.welcome.enabled'; const telemetryFrom = 'welcomePage'; export class WelcomePageContribution implements IWorkbenchContribution { constructor( @IInstantiationService instantiationService: IInstantiationService, @IConfigurationService configurationService: IConfigurationService, @IEditorService editorService: IEditorService, @IBackupFileService backupFileService: IBackupFileService, @IFileService fileService: IFileService, @IWorkspaceContextService contextService: IWorkspaceContextService, @ILifecycleService lifecycleService: ILifecycleService, @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, @ICommandService private readonly commandService: ICommandService, ) { const enabled = isWelcomePageEnabled(configurationService, contextService); if (enabled && lifecycleService.startupKind !== StartupKind.ReloadedWindow) { backupFileService.hasBackups().then(hasBackups => { // Open the welcome even if we opened a set of default editors if ((!editorService.activeEditor || layoutService.openedDefaultEditors) && !hasBackups) { const openWithReadme = configurationService.getValue(configurationKey) === 'readme'; if (openWithReadme) { return Promise.all(contextService.getWorkspace().folders.map(folder => { const folderUri = folder.uri; return fileService.resolve(folderUri) .then(folder => { const files = folder.children ? folder.children.map(child => child.name) : []; const file = files.sort().find(file => file.toLowerCase().startsWith('readme')); if (file) { return joinPath(folderUri, file); } return undefined; }, onUnexpectedError); })).then(arrays.coalesce) .then(readmes => { if (!editorService.activeEditor) { if (readmes.length) { const isMarkDown = (readme: URI) => readme.path.toLowerCase().endsWith('.md'); return Promise.all([ this.commandService.executeCommand('markdown.showPreview', null, readmes.filter(isMarkDown), { locked: true }), editorService.openEditors(readmes.filter(readme => !isMarkDown(readme)) .map(readme => ({ resource: readme }))), ]); } else { return instantiationService.createInstance(WelcomePage).openEditor(); } } return undefined; }); } else { let options: IEditorOptions; let editor = editorService.activeEditor; if (editor) { // Ensure that the welcome editor won't get opened more than once if (editor.getTypeId() === welcomeInputTypeId || editorService.editors.some(e => e.getTypeId() === welcomeInputTypeId)) { return undefined; } options = { pinned: false, index: 0 }; } else { options = { pinned: false }; } return instantiationService.createInstance(WelcomePage).openEditor(options); } } return undefined; }).then(undefined, onUnexpectedError); } } } function isWelcomePageEnabled(configurationService: IConfigurationService, contextService: IWorkspaceContextService) { const startupEditor = configurationService.inspect(configurationKey); if (!startupEditor.userValue && !startupEditor.workspaceValue) { const welcomeEnabled = configurationService.inspect(oldConfigurationKey); if (welcomeEnabled.value !== undefined && welcomeEnabled.value !== null) { return welcomeEnabled.value; } } return startupEditor.value === 'welcomePage' || startupEditor.value === 'readme' || startupEditor.value === 'welcomePageInEmptyWorkbench' && contextService.getWorkbenchState() === WorkbenchState.EMPTY; } export class WelcomePageAction extends Action { public static readonly ID = 'workbench.action.showWelcomePage'; public static readonly LABEL = localize('welcomePage', "Welcome"); constructor( id: string, label: string, @IInstantiationService private readonly instantiationService: IInstantiationService ) { super(id, label); } public run(): Promise { return this.instantiationService.createInstance(WelcomePage) .openEditor() .then(() => undefined); } } interface ExtensionSuggestion { name: string; title?: string; id: string; isKeymap?: boolean; isCommand?: boolean; } const extensionPacks: ExtensionSuggestion[] = [ { name: localize('welcomePage.javaScript', "JavaScript"), id: 'dbaeumer.vscode-eslint' }, { name: localize('welcomePage.python', "Python"), id: 'ms-python.python' }, { name: localize('welcomePage.java', "Java"), id: 'vscjava.vscode-java-pack' }, { name: localize('welcomePage.php', "PHP"), id: 'felixfbecker.php-pack' }, { name: localize('welcomePage.azure', "Azure"), title: localize('welcomePage.showAzureExtensions', "Show Azure extensions"), id: 'workbench.extensions.action.showAzureExtensions', isCommand: true }, { name: localize('welcomePage.docker', "Docker"), id: 'ms-azuretools.vscode-docker' }, ]; const keymapExtensions: ExtensionSuggestion[] = [ { name: localize('welcomePage.vim', "Vim"), id: 'vscodevim.vim', isKeymap: true }, { name: localize('welcomePage.sublime', "Sublime"), id: 'ms-vscode.sublime-keybindings', isKeymap: true }, { name: localize('welcomePage.atom', "Atom"), id: 'ms-vscode.atom-keybindings', isKeymap: true }, ]; interface Strings { installEvent: string; installedEvent: string; detailsEvent: string; alreadyInstalled: string; reloadAfterInstall: string; installing: string; extensionNotFound: string; } /* __GDPR__ "installExtension" : { "${include}": [ "${WelcomePageInstall-1}" ] } */ /* __GDPR__ "installedExtension" : { "${include}": [ "${WelcomePageInstalled-1}", "${WelcomePageInstalled-2}", "${WelcomePageInstalled-3}", "${WelcomePageInstalled-4}", "${WelcomePageInstalled-6}" ] } */ /* __GDPR__ "detailsExtension" : { "${include}": [ "${WelcomePageDetails-1}" ] } */ const extensionPackStrings: Strings = { installEvent: 'installExtension', installedEvent: 'installedExtension', detailsEvent: 'detailsExtension', alreadyInstalled: localize('welcomePage.extensionPackAlreadyInstalled', "Support for {0} is already installed."), reloadAfterInstall: localize('welcomePage.willReloadAfterInstallingExtensionPack', "The window will reload after installing additional support for {0}."), installing: localize('welcomePage.installingExtensionPack', "Installing additional support for {0}..."), extensionNotFound: localize('welcomePage.extensionPackNotFound', "Support for {0} with id {1} could not be found."), }; CommandsRegistry.registerCommand('workbench.extensions.action.showAzureExtensions', accessor => { const viewletService = accessor.get(IViewletService); return viewletService.openViewlet(VIEWLET_ID, true) .then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer) .then(viewlet => { viewlet.search('@sort:installs azure '); viewlet.focus(); }); }); /* __GDPR__ "installKeymap" : { "${include}": [ "${WelcomePageInstall-1}" ] } */ /* __GDPR__ "installedKeymap" : { "${include}": [ "${WelcomePageInstalled-1}", "${WelcomePageInstalled-2}", "${WelcomePageInstalled-3}", "${WelcomePageInstalled-4}", "${WelcomePageInstalled-6}" ] } */ /* __GDPR__ "detailsKeymap" : { "${include}": [ "${WelcomePageDetails-1}" ] } */ const keymapStrings: Strings = { installEvent: 'installKeymap', installedEvent: 'installedKeymap', detailsEvent: 'detailsKeymap', alreadyInstalled: localize('welcomePage.keymapAlreadyInstalled', "The {0} keyboard shortcuts are already installed."), reloadAfterInstall: localize('welcomePage.willReloadAfterInstallingKeymap', "The window will reload after installing the {0} keyboard shortcuts."), installing: localize('welcomePage.installingKeymap', "Installing the {0} keyboard shortcuts..."), extensionNotFound: localize('welcomePage.keymapNotFound', "The {0} keyboard shortcuts with id {1} could not be found."), }; const welcomeInputTypeId = 'workbench.editors.welcomePageInput'; class WelcomePage extends Disposable { readonly editorInput: WalkThroughInput; constructor( @IEditorService private readonly editorService: IEditorService, @IInstantiationService private readonly instantiationService: IInstantiationService, @IWorkspacesService private readonly workspacesService: IWorkspacesService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @IConfigurationService private readonly configurationService: IConfigurationService, @ILabelService private readonly labelService: ILabelService, @INotificationService private readonly notificationService: INotificationService, @IWorkbenchExtensionEnablementService private readonly extensionEnablementService: IWorkbenchExtensionEnablementService, @IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService, @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, @IExtensionRecommendationsService private readonly tipsService: IExtensionRecommendationsService, @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @ILifecycleService lifecycleService: ILifecycleService, @ITelemetryService private readonly telemetryService: ITelemetryService, @IHostService private readonly hostService: IHostService, @IProductService private readonly productService: IProductService, ) { super(); this._register(lifecycleService.onShutdown(() => this.dispose())); const recentlyOpened = this.workspacesService.getRecentlyOpened(); const installedExtensions = this.instantiationService.invokeFunction(getInstalledExtensions); const resource = URI.parse(require.toUrl('./vs_code_welcome_page')) .with({ scheme: Schemas.walkThrough, query: JSON.stringify({ moduleId: 'vs/workbench/contrib/welcome/page/browser/vs_code_welcome_page' }) }); this.editorInput = this.instantiationService.createInstance(WalkThroughInput, { typeId: welcomeInputTypeId, name: localize('welcome.title', "Welcome"), resource, telemetryFrom, onReady: (container: HTMLElement) => this.onReady(container, recentlyOpened, installedExtensions) }); } public openEditor(options: IEditorOptions = { pinned: false }) { return this.editorService.openEditor(this.editorInput, options); } private onReady(container: HTMLElement, recentlyOpened: Promise, installedExtensions: Promise): void { const enabled = isWelcomePageEnabled(this.configurationService, this.contextService); const showOnStartup = container.querySelector('#showOnStartup'); if (enabled) { showOnStartup.setAttribute('checked', 'checked'); } showOnStartup.addEventListener('click', e => { this.configurationService.updateValue(configurationKey, showOnStartup.checked ? 'welcomePage' : 'newUntitledFile', ConfigurationTarget.USER); }); const prodName = container.querySelector('.welcomePage .title .caption') as HTMLElement; if (prodName) { prodName.textContent = this.productService.nameLong; } recentlyOpened.then(({ workspaces }) => { // Filter out the current workspace workspaces = workspaces.filter(recent => !this.contextService.isCurrentWorkspace(isRecentWorkspace(recent) ? recent.workspace : recent.folderUri)); if (!workspaces.length) { const recent = container.querySelector('.welcomePage') as HTMLElement; recent.classList.add('emptyRecent'); return; } const ul = container.querySelector('.recent ul'); if (!ul) { return; } const moreRecent = ul.querySelector('.moreRecent')!; const workspacesToShow = workspaces.slice(0, 5); const updateEntries = () => { const listEntries = this.createListEntries(workspacesToShow); while (ul.firstChild) { ul.removeChild(ul.firstChild); } ul.append(...listEntries, moreRecent); }; updateEntries(); this._register(this.labelService.onDidChangeFormatters(updateEntries)); }).then(undefined, onUnexpectedError); this.addExtensionList(container, '.extensionPackList', extensionPacks, extensionPackStrings); this.addExtensionList(container, '.keymapList', keymapExtensions, keymapStrings); this.updateInstalledExtensions(container, installedExtensions); this._register(this.instantiationService.invokeFunction(onExtensionChanged)(ids => { for (const id of ids) { if (container.querySelector(`.installExtension[data-extension="${id.id}"], .enabledExtension[data-extension="${id.id}"]`)) { const installedExtensions = this.instantiationService.invokeFunction(getInstalledExtensions); this.updateInstalledExtensions(container, installedExtensions); break; } } })); } private createListEntries(recents: (IRecentWorkspace | IRecentFolder)[]) { return recents.map(recent => { let fullPath: string; let windowOpenable: IWindowOpenable; if (isRecentFolder(recent)) { windowOpenable = { folderUri: recent.folderUri }; fullPath = recent.label || this.labelService.getWorkspaceLabel(recent.folderUri, { verbose: true }); } else { fullPath = recent.label || this.labelService.getWorkspaceLabel(recent.workspace, { verbose: true }); windowOpenable = { workspaceUri: recent.workspace.configPath }; } const { name, parentPath } = splitName(fullPath); const li = document.createElement('li'); const a = document.createElement('a'); a.innerText = name; a.title = fullPath; a.setAttribute('aria-label', localize('welcomePage.openFolderWithPath', "Open folder {0} with path {1}", name, parentPath)); a.href = 'javascript:void(0)'; a.addEventListener('click', e => { this.telemetryService.publicLog2('workbenchActionExecuted', { id: 'openRecentFolder', from: telemetryFrom }); this.hostService.openWindow([windowOpenable], { forceNewWindow: e.ctrlKey || e.metaKey }); e.preventDefault(); e.stopPropagation(); }); li.appendChild(a); const span = document.createElement('span'); span.classList.add('path'); span.classList.add('detail'); span.innerText = parentPath; span.title = fullPath; li.appendChild(span); return li; }); } private addExtensionList(container: HTMLElement, listSelector: string, suggestions: ExtensionSuggestion[], strings: Strings) { const list = container.querySelector(listSelector); if (list) { suggestions.forEach((extension, i) => { if (i) { list.appendChild(document.createTextNode(localize('welcomePage.extensionListSeparator', ", "))); } const a = document.createElement('a'); a.innerText = extension.name; a.title = extension.title || (extension.isKeymap ? localize('welcomePage.installKeymap', "Install {0} keymap", extension.name) : localize('welcomePage.installExtensionPack', "Install additional support for {0}", extension.name)); if (extension.isCommand) { a.href = `command:${extension.id}`; list.appendChild(a); } else { a.classList.add('installExtension'); a.setAttribute('data-extension', extension.id); a.href = 'javascript:void(0)'; a.addEventListener('click', e => { this.installExtension(extension, strings); e.preventDefault(); e.stopPropagation(); }); list.appendChild(a); const span = document.createElement('span'); span.innerText = extension.name; span.title = extension.isKeymap ? localize('welcomePage.installedKeymap', "{0} keymap is already installed", extension.name) : localize('welcomePage.installedExtensionPack', "{0} support is already installed", extension.name); span.classList.add('enabledExtension'); span.setAttribute('data-extension', extension.id); list.appendChild(span); } }); } } private installExtension(extensionSuggestion: ExtensionSuggestion, strings: Strings): void { /* __GDPR__FRAGMENT__ "WelcomePageInstall-1" : { "from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "extensionId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } } */ this.telemetryService.publicLog(strings.installEvent, { from: telemetryFrom, extensionId: extensionSuggestion.id, }); this.instantiationService.invokeFunction(getInstalledExtensions).then(extensions => { const installedExtension = extensions.find(extension => areSameExtensions(extension.identifier, { id: extensionSuggestion.id })); if (installedExtension && installedExtension.globallyEnabled) { /* __GDPR__FRAGMENT__ "WelcomePageInstalled-1" : { "from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "extensionId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "outcome": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } } */ this.telemetryService.publicLog(strings.installedEvent, { from: telemetryFrom, extensionId: extensionSuggestion.id, outcome: 'already_enabled', }); this.notificationService.info(strings.alreadyInstalled.replace('{0}', extensionSuggestion.name)); return; } const foundAndInstalled = installedExtension ? Promise.resolve(installedExtension.local) : this.extensionGalleryService.query({ names: [extensionSuggestion.id], source: telemetryFrom }, CancellationToken.None) .then((result): null | Promise => { const [extension] = result.firstPage; if (!extension) { return null; } return this.extensionManagementService.installFromGallery(extension) .then(() => this.extensionManagementService.getInstalled(ExtensionType.User)) .then(installed => { const local = installed.filter(i => areSameExtensions(extension.identifier, i.identifier))[0]; // TODO: Do this as part of the install to avoid multiple events. return this.extensionEnablementService.setEnablement([local], EnablementState.DisabledGlobally).then(() => local); }); }); this.notificationService.prompt( Severity.Info, strings.reloadAfterInstall.replace('{0}', extensionSuggestion.name), [{ label: localize('ok', "OK"), run: () => { const messageDelay = new TimeoutTimer(); messageDelay.cancelAndSet(() => { this.notificationService.info(strings.installing.replace('{0}', extensionSuggestion.name)); }, 300); const extensionsToDisable = extensions.filter(extension => isKeymapExtension(this.tipsService, extension) && extension.globallyEnabled).map(extension => extension.local); extensionsToDisable.length ? this.extensionEnablementService.setEnablement(extensionsToDisable, EnablementState.DisabledGlobally) : Promise.resolve() .then(() => { return foundAndInstalled.then(foundExtension => { messageDelay.cancel(); if (foundExtension) { return this.extensionEnablementService.setEnablement([foundExtension], EnablementState.EnabledGlobally) .then(() => { /* __GDPR__FRAGMENT__ "WelcomePageInstalled-2" : { "from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "extensionId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "outcome": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } } */ this.telemetryService.publicLog(strings.installedEvent, { from: telemetryFrom, extensionId: extensionSuggestion.id, outcome: installedExtension ? 'enabled' : 'installed', }); return this.hostService.reload(); }); } else { /* __GDPR__FRAGMENT__ "WelcomePageInstalled-3" : { "from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "extensionId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "outcome": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } } */ this.telemetryService.publicLog(strings.installedEvent, { from: telemetryFrom, extensionId: extensionSuggestion.id, outcome: 'not_found', }); this.notificationService.error(strings.extensionNotFound.replace('{0}', extensionSuggestion.name).replace('{1}', extensionSuggestion.id)); return undefined; } }); }).then(undefined, err => { /* __GDPR__FRAGMENT__ "WelcomePageInstalled-4" : { "from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "extensionId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "outcome": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } } */ this.telemetryService.publicLog(strings.installedEvent, { from: telemetryFrom, extensionId: extensionSuggestion.id, outcome: isPromiseCanceledError(err) ? 'canceled' : 'error', }); this.notificationService.error(err); }); } }, { label: localize('details', "Details"), run: () => { /* __GDPR__FRAGMENT__ "WelcomePageDetails-1" : { "from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "extensionId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } } */ this.telemetryService.publicLog(strings.detailsEvent, { from: telemetryFrom, extensionId: extensionSuggestion.id, }); this.extensionsWorkbenchService.queryGallery({ names: [extensionSuggestion.id] }, CancellationToken.None) .then(result => this.extensionsWorkbenchService.open(result.firstPage[0])) .then(undefined, onUnexpectedError); } }] ); }).then(undefined, err => { /* __GDPR__FRAGMENT__ "WelcomePageInstalled-6" : { "from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "extensionId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "outcome": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } } */ this.telemetryService.publicLog(strings.installedEvent, { from: telemetryFrom, extensionId: extensionSuggestion.id, outcome: isPromiseCanceledError(err) ? 'canceled' : 'error', }); this.notificationService.error(err); }); } private updateInstalledExtensions(container: HTMLElement, installedExtensions: Promise) { installedExtensions.then(extensions => { const elements = container.querySelectorAll('.installExtension, .enabledExtension'); for (let i = 0; i < elements.length; i++) { elements[i].classList.remove('installed'); } extensions.filter(ext => ext.globallyEnabled) .map(ext => ext.identifier.id) .forEach(id => { const install = container.querySelectorAll(`.installExtension[data-extension="${id}"]`); for (let i = 0; i < install.length; i++) { install[i].classList.add('installed'); } const enabled = container.querySelectorAll(`.enabledExtension[data-extension="${id}"]`); for (let i = 0; i < enabled.length; i++) { enabled[i].classList.add('installed'); } }); }).then(undefined, onUnexpectedError); } } export class WelcomeInputFactory implements IEditorInputFactory { static readonly ID = welcomeInputTypeId; public canSerialize(editorInput: EditorInput): boolean { return true; } public serialize(editorInput: EditorInput): string { return '{}'; } public deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): WalkThroughInput { return instantiationService.createInstance(WelcomePage) .editorInput; } } // theming export const buttonBackground = registerColor('welcomePage.buttonBackground', { dark: null, light: null, hc: null }, localize('welcomePage.buttonBackground', 'Background color for the buttons on the Welcome page.')); export const buttonHoverBackground = registerColor('welcomePage.buttonHoverBackground', { dark: null, light: null, hc: null }, localize('welcomePage.buttonHoverBackground', 'Hover background color for the buttons on the Welcome page.')); export const welcomePageBackground = registerColor('welcomePage.background', { light: null, dark: null, hc: null }, localize('welcomePage.background', 'Background color for the Welcome page.')); registerThemingParticipant((theme, collector) => { const backgroundColor = theme.getColor(welcomePageBackground); if (backgroundColor) { collector.addRule(`.monaco-workbench .part.editor > .content .welcomePageContainer { background-color: ${backgroundColor}; }`); } const foregroundColor = theme.getColor(foreground); if (foregroundColor) { collector.addRule(`.monaco-workbench .part.editor > .content .welcomePage .caption { color: ${foregroundColor}; }`); } const descriptionColor = theme.getColor(descriptionForeground); if (descriptionColor) { collector.addRule(`.monaco-workbench .part.editor > .content .welcomePage .detail { color: ${descriptionColor}; }`); } const buttonColor = getExtraColor(theme, buttonBackground, { dark: 'rgba(0, 0, 0, .2)', extra_dark: 'rgba(200, 235, 255, .042)', light: 'rgba(0,0,0,.04)', hc: 'black' }); if (buttonColor) { collector.addRule(`.monaco-workbench .part.editor > .content .welcomePage .commands .item button { background: ${buttonColor}; }`); } const buttonHoverColor = getExtraColor(theme, buttonHoverBackground, { dark: 'rgba(200, 235, 255, .072)', extra_dark: 'rgba(200, 235, 255, .072)', light: 'rgba(0,0,0,.10)', hc: null }); if (buttonHoverColor) { collector.addRule(`.monaco-workbench .part.editor > .content .welcomePage .commands .item button:hover { background: ${buttonHoverColor}; }`); } const link = theme.getColor(textLinkForeground); if (link) { collector.addRule(`.monaco-workbench .part.editor > .content .welcomePage a { color: ${link}; }`); } const activeLink = theme.getColor(textLinkActiveForeground); if (activeLink) { collector.addRule(`.monaco-workbench .part.editor > .content .welcomePage a:hover, .monaco-workbench .part.editor > .content .welcomePage a:active { color: ${activeLink}; }`); } const focusColor = theme.getColor(focusBorder); if (focusColor) { collector.addRule(`.monaco-workbench .part.editor > .content .welcomePage a:focus { outline-color: ${focusColor}; }`); } const border = theme.getColor(contrastBorder); if (border) { collector.addRule(`.monaco-workbench .part.editor > .content .welcomePage .commands .item button { border-color: ${border}; }`); } const activeBorder = theme.getColor(activeContrastBorder); if (activeBorder) { collector.addRule(`.monaco-workbench .part.editor > .content .welcomePage .commands .item button:hover { outline-color: ${activeBorder}; }`); } });