diff --git a/extensions/typescript-language-features/src/experimentationService.ts b/extensions/typescript-language-features/src/experimentationService.ts index 5dc458277d46d..9bb49c8926210 100644 --- a/extensions/typescript-language-features/src/experimentationService.ts +++ b/extensions/typescript-language-features/src/experimentationService.ts @@ -9,7 +9,7 @@ import * as tas from 'vscode-tas-client'; import { IExperimentationTelemetryReporter } from './experimentTelemetryReporter'; interface ExperimentTypes { - // None for now. + suggestNativePreview: boolean; } export class ExperimentationService { @@ -24,8 +24,8 @@ export class ExperimentationService { public async getTreatmentVariable(name: K, defaultValue: ExperimentTypes[K]): Promise { const experimentationService = await this._experimentationServicePromise; try { - const treatmentVariable = experimentationService.getTreatmentVariableAsync('vscode', name, /*checkCache*/ true) as Promise; - return treatmentVariable; + const treatmentVariable = await experimentationService.getTreatmentVariableAsync('vscode', name, /*checkCache*/ true) as ExperimentTypes[K]; + return treatmentVariable ?? defaultValue; } catch { return defaultValue; } @@ -36,7 +36,8 @@ export async function createTasExperimentationService( reporter: IExperimentationTelemetryReporter, id: string, version: string, - globalState: vscode.Memento): Promise { + globalState: vscode.Memento +): Promise { let targetPopulation: tas.TargetPopulation; switch (vscode.env.uriScheme) { case 'vscode': diff --git a/extensions/typescript-language-features/src/extension.ts b/extensions/typescript-language-features/src/extension.ts index fb1ae1967d4bd..4b9a4533d3f5f 100644 --- a/extensions/typescript-language-features/src/extension.ts +++ b/extensions/typescript-language-features/src/extension.ts @@ -21,6 +21,7 @@ import { PluginManager } from './tsServer/plugins'; import { ElectronServiceProcessFactory } from './tsServer/serverProcess.electron'; import { DiskTypeScriptVersionProvider } from './tsServer/versionProvider.electron'; import { ActiveJsTsEditorTracker } from './ui/activeJsTsEditorTracker'; +import { suggestNativePreview } from './ui/suggestNativePreview'; import { onCaseInsensitiveFileSystem } from './utils/fs.electron'; import { Lazy } from './utils/lazy'; import { getPackageInfo } from './utils/packageInfo'; @@ -48,9 +49,8 @@ export function activate( experimentTelemetryReporter = new ExperimentationTelemetryReporter(vscTelemetryReporter); context.subscriptions.push(experimentTelemetryReporter); - // Currently we have no experiments, but creating the service adds the appropriate - // shared properties to the ExperimentationTelemetryReporter we just created. - new ExperimentationService(experimentTelemetryReporter, id, version, context.globalState); + const experimentationService = new ExperimentationService(experimentTelemetryReporter, id, version, context.globalState); + suggestNativePreview(context, experimentationService); } // Register features that work in both TSGO and non-TSGO modes diff --git a/extensions/typescript-language-features/src/ui/suggestNativePreview.ts b/extensions/typescript-language-features/src/ui/suggestNativePreview.ts new file mode 100644 index 0000000000000..8b919b95bde57 --- /dev/null +++ b/extensions/typescript-language-features/src/ui/suggestNativePreview.ts @@ -0,0 +1,61 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +import { tsNativeExtensionId } from '../commands/useTsgo'; +import { ExperimentationService } from '../experimentationService'; + +const suggestNativePreviewStorageKey = 'typescript.suggestNativePreview.dismissed'; + +export async function suggestNativePreview( + context: vscode.ExtensionContext, + experimentationService: ExperimentationService, +): Promise { + if (context.globalState.get(suggestNativePreviewStorageKey)) { + return; + } + + // Only show when the window is active + if (!vscode.window.state.active) { + return; + } + + // Only show when the nightly extension is installed + if (!vscode.extensions.getExtension('ms-vscode.vscode-typescript-next')) { + return; + } + + // Don't show if the native preview extension is already installed + if (vscode.extensions.getExtension(tsNativeExtensionId)) { + // Also don't prompt in the future + await context.globalState.update(suggestNativePreviewStorageKey, true); + return; + } + + const inExperiment = await experimentationService.getTreatmentVariable('suggestNativePreview', false); + if (!inExperiment) { + return; + } + + const install: vscode.MessageItem = { title: vscode.l10n.t("Install") }; + const learnMore: vscode.MessageItem = { title: vscode.l10n.t("Learn More") }; + const dismiss: vscode.MessageItem = { title: vscode.l10n.t("Don't Show Again") }; + + const selection = await vscode.window.showInformationMessage( + vscode.l10n.t("Try TypeScript 7 Native Preview for significantly faster type checking and language features."), + {}, + install, + learnMore, + dismiss, + ); + // Don't show again + await context.globalState.update(suggestNativePreviewStorageKey, true); + + if (selection === install) { + await vscode.commands.executeCommand('workbench.extensions.installExtension', tsNativeExtensionId); + } else if (selection === learnMore) { + await vscode.env.openExternal(vscode.Uri.parse('https://aka.ms/vscode-try-ts-7-learn-more')); + } +}