diff --git a/package.json b/package.json index df2d2546e4d8..47faec663015 100644 --- a/package.json +++ b/package.json @@ -22,8 +22,7 @@ "quickPickSortByLabel", "testObserver", "quickPickItemTooltip", - "saveEditor", - "terminalDataWriteEvent" + "saveEditor" ], "author": { "name": "Microsoft Corporation" diff --git a/src/client/common/application/applicationShell.ts b/src/client/common/application/applicationShell.ts index aadf80186900..454662472010 100644 --- a/src/client/common/application/applicationShell.ts +++ b/src/client/common/application/applicationShell.ts @@ -10,7 +10,6 @@ import { DocumentSelector, env, Event, - EventEmitter, InputBox, InputBoxOptions, languages, @@ -38,8 +37,7 @@ import { WorkspaceFolder, WorkspaceFolderPickOptions, } from 'vscode'; -import { traceError } from '../../logging'; -import { IApplicationShell, TerminalDataWriteEvent } from './types'; +import { IApplicationShell } from './types'; @injectable() export class ApplicationShell implements IApplicationShell { @@ -174,12 +172,4 @@ export class ApplicationShell implements IApplicationShell { public createLanguageStatusItem(id: string, selector: DocumentSelector): LanguageStatusItem { return languages.createLanguageStatusItem(id, selector); } - public get onDidWriteTerminalData(): Event { - try { - return window.onDidWriteTerminalData; - } catch (ex) { - traceError('Failed to get proposed API onDidWriteTerminalData', ex); - return new EventEmitter().event; - } - } } diff --git a/src/client/common/application/types.ts b/src/client/common/application/types.ts index 863f5e4651b2..fa2ced6c45da 100644 --- a/src/client/common/application/types.ts +++ b/src/client/common/application/types.ts @@ -67,17 +67,6 @@ import { Resource } from '../types'; import { ICommandNameArgumentTypeMapping } from './commands'; import { ExtensionContextKey } from './contextKeys'; -export interface TerminalDataWriteEvent { - /** - * The {@link Terminal} for which the data was written. - */ - readonly terminal: Terminal; - /** - * The data being written. - */ - readonly data: string; -} - export const IApplicationShell = Symbol('IApplicationShell'); export interface IApplicationShell { /** @@ -86,13 +75,6 @@ export interface IApplicationShell { */ readonly onDidChangeWindowState: Event; - /** - * An event which fires when the terminal's child pseudo-device is written to (the shell). - * In other words, this provides access to the raw data stream from the process running - * within the terminal, including VT sequences. - */ - readonly onDidWriteTerminalData: Event; - showInformationMessage(message: string, ...items: string[]): Thenable; /** diff --git a/src/client/common/utils/localize.ts b/src/client/common/utils/localize.ts index fc118699d2c7..bc32c1078cad 100644 --- a/src/client/common/utils/localize.ts +++ b/src/client/common/utils/localize.ts @@ -201,10 +201,6 @@ export namespace Interpreters { export const terminalEnvVarCollectionPrompt = l10n.t( 'The Python extension automatically activates all terminals using the selected environment, even when the name of the environment{0} is not present in the terminal prompt. [Learn more](https://aka.ms/vscodePythonTerminalActivation).', ); - export const terminalDeactivatePrompt = l10n.t( - 'Deactivating virtual environments may not work by default due to a technical limitation in our activation approach, but it can be resolved with a few simple steps.', - ); - export const deactivateDoneButton = l10n.t('Done, it works'); export const activatedCondaEnvLaunch = l10n.t( 'We noticed VS Code was launched from an activated conda environment, would you like to select it?', ); diff --git a/src/client/terminals/envCollectionActivation/indicatorPrompt.ts b/src/client/interpreter/activation/terminalEnvVarCollectionPrompt.ts similarity index 95% rename from src/client/terminals/envCollectionActivation/indicatorPrompt.ts rename to src/client/interpreter/activation/terminalEnvVarCollectionPrompt.ts index bf648eefe8e9..c8aea205a32a 100644 --- a/src/client/terminals/envCollectionActivation/indicatorPrompt.ts +++ b/src/client/interpreter/activation/terminalEnvVarCollectionPrompt.ts @@ -14,15 +14,15 @@ import { } from '../../common/types'; import { Common, Interpreters } from '../../common/utils/localize'; import { IExtensionSingleActivationService } from '../../activation/types'; +import { ITerminalEnvVarCollectionService } from './types'; import { inTerminalEnvVarExperiment } from '../../common/experiments/helpers'; -import { IInterpreterService } from '../../interpreter/contracts'; +import { IInterpreterService } from '../contracts'; import { PythonEnvironment } from '../../pythonEnvironments/info'; -import { ITerminalEnvVarCollectionService } from '../types'; export const terminalEnvCollectionPromptKey = 'TERMINAL_ENV_COLLECTION_PROMPT_KEY'; @injectable() -export class TerminalIndicatorPrompt implements IExtensionSingleActivationService { +export class TerminalEnvVarCollectionPrompt implements IExtensionSingleActivationService { public readonly supportedWorkspaceTypes = { untrustedWorkspace: false, virtualWorkspace: false }; constructor( diff --git a/src/client/terminals/envCollectionActivation/service.ts b/src/client/interpreter/activation/terminalEnvVarCollectionService.ts similarity index 98% rename from src/client/terminals/envCollectionActivation/service.ts rename to src/client/interpreter/activation/terminalEnvVarCollectionService.ts index ae346d264eeb..c11ec221d4d7 100644 --- a/src/client/terminals/envCollectionActivation/service.ts +++ b/src/client/interpreter/activation/terminalEnvVarCollectionService.ts @@ -28,9 +28,9 @@ import { import { Deferred, createDeferred } from '../../common/utils/async'; import { Interpreters } from '../../common/utils/localize'; import { traceDecoratorVerbose, traceError, traceVerbose, traceWarn } from '../../logging'; -import { IInterpreterService } from '../../interpreter/contracts'; -import { defaultShells } from '../../interpreter/activation/service'; -import { IEnvironmentActivationService } from '../../interpreter/activation/types'; +import { IInterpreterService } from '../contracts'; +import { defaultShells } from './service'; +import { IEnvironmentActivationService, ITerminalEnvVarCollectionService } from './types'; import { EnvironmentType, PythonEnvironment } from '../../pythonEnvironments/info'; import { getSearchPathEnvVarNames } from '../../common/utils/exec'; import { EnvironmentVariables } from '../../common/variables/types'; @@ -38,7 +38,6 @@ import { TerminalShellType } from '../../common/terminal/types'; import { OSType } from '../../common/utils/platform'; import { normCase } from '../../common/platform/fs-paths'; import { PythonEnvType } from '../../pythonEnvironments/base/info'; -import { ITerminalEnvVarCollectionService } from '../types'; @injectable() export class TerminalEnvVarCollectionService implements IExtensionActivationService, ITerminalEnvVarCollectionService { diff --git a/src/client/interpreter/activation/types.ts b/src/client/interpreter/activation/types.ts index e00ef9b62b3f..2b364cbeb862 100644 --- a/src/client/interpreter/activation/types.ts +++ b/src/client/interpreter/activation/types.ts @@ -21,3 +21,11 @@ export interface IEnvironmentActivationService { interpreter?: PythonEnvironment, ): Promise; } + +export const ITerminalEnvVarCollectionService = Symbol('ITerminalEnvVarCollectionService'); +export interface ITerminalEnvVarCollectionService { + /** + * Returns true if we know with high certainity the terminal prompt is set correctly for a particular resource. + */ + isTerminalPromptSetCorrectly(resource?: Resource): boolean; +} diff --git a/src/client/interpreter/serviceRegistry.ts b/src/client/interpreter/serviceRegistry.ts index 422776bd5e43..018e7abfdc46 100644 --- a/src/client/interpreter/serviceRegistry.ts +++ b/src/client/interpreter/serviceRegistry.ts @@ -6,7 +6,9 @@ import { IExtensionActivationService, IExtensionSingleActivationService } from '../activation/types'; import { IServiceManager } from '../ioc/types'; import { EnvironmentActivationService } from './activation/service'; -import { IEnvironmentActivationService } from './activation/types'; +import { TerminalEnvVarCollectionPrompt } from './activation/terminalEnvVarCollectionPrompt'; +import { TerminalEnvVarCollectionService } from './activation/terminalEnvVarCollectionService'; +import { IEnvironmentActivationService, ITerminalEnvVarCollectionService } from './activation/types'; import { InterpreterAutoSelectionService } from './autoSelection/index'; import { InterpreterAutoSelectionProxyService } from './autoSelection/proxy'; import { IInterpreterAutoSelectionService, IInterpreterAutoSelectionProxyService } from './autoSelection/types'; @@ -108,4 +110,13 @@ export function registerTypes(serviceManager: IServiceManager): void { IEnvironmentActivationService, EnvironmentActivationService, ); + serviceManager.addSingleton( + ITerminalEnvVarCollectionService, + TerminalEnvVarCollectionService, + ); + serviceManager.addBinding(ITerminalEnvVarCollectionService, IExtensionActivationService); + serviceManager.addSingleton( + IExtensionSingleActivationService, + TerminalEnvVarCollectionPrompt, + ); } diff --git a/src/client/telemetry/constants.ts b/src/client/telemetry/constants.ts index 4b4dc302dc3f..c680b91094cb 100644 --- a/src/client/telemetry/constants.ts +++ b/src/client/telemetry/constants.ts @@ -29,7 +29,6 @@ export enum EventName { TERMINAL_SHELL_IDENTIFICATION = 'TERMINAL_SHELL_IDENTIFICATION', PYTHON_INTERPRETER_ACTIVATE_ENVIRONMENT_PROMPT = 'PYTHON_INTERPRETER_ACTIVATE_ENVIRONMENT_PROMPT', PYTHON_NOT_INSTALLED_PROMPT = 'PYTHON_NOT_INSTALLED_PROMPT', - TERMINAL_DEACTIVATE_PROMPT = 'TERMINAL_DEACTIVATE_PROMPT', CONDA_INHERIT_ENV_PROMPT = 'CONDA_INHERIT_ENV_PROMPT', REQUIRE_JUPYTER_PROMPT = 'REQUIRE_JUPYTER_PROMPT', ACTIVATED_CONDA_ENV_LAUNCH = 'ACTIVATED_CONDA_ENV_LAUNCH', diff --git a/src/client/telemetry/index.ts b/src/client/telemetry/index.ts index bd60b9281a93..600f9a2d48ff 100644 --- a/src/client/telemetry/index.ts +++ b/src/client/telemetry/index.ts @@ -1328,24 +1328,6 @@ export interface IEventNamePropertyMapping { */ selection: 'Allow' | 'Close' | undefined; }; - /** - * Telemetry event sent with details when user clicks the prompt with the following message: - * - * 'Deactivating virtual environments may not work by default due to a technical limitation in our activation approach, but it can be resolved with a few simple steps.' - */ - /* __GDPR__ - "terminal_deactivate_prompt" : { - "selection" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "karrtikr" } - } - */ - [EventName.TERMINAL_DEACTIVATE_PROMPT]: { - /** - * `See Instructions` When 'See Instructions' option is selected - * `Done, it works` When 'Done, it works' option is selected - * `Don't show again` When 'Don't show again' option is selected - */ - selection: 'See Instructions' | 'Done, it works' | "Don't show again" | undefined; - }; /** * Telemetry event sent with details when user attempts to run in interactive window when Jupyter is not installed. */ diff --git a/src/client/terminals/envCollectionActivation/deactivatePrompt.ts b/src/client/terminals/envCollectionActivation/deactivatePrompt.ts deleted file mode 100644 index 460144303f18..000000000000 --- a/src/client/terminals/envCollectionActivation/deactivatePrompt.ts +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import { inject, injectable } from 'inversify'; -import { Uri } from 'vscode'; -import { IApplicationEnvironment, IApplicationShell } from '../../common/application/types'; -import { IBrowserService, IDisposableRegistry, IExperimentService, IPersistentStateFactory } from '../../common/types'; -import { Common, Interpreters } from '../../common/utils/localize'; -import { IExtensionSingleActivationService } from '../../activation/types'; -import { inTerminalEnvVarExperiment } from '../../common/experiments/helpers'; -import { IInterpreterService } from '../../interpreter/contracts'; -import { PythonEnvType } from '../../pythonEnvironments/base/info'; -import { identifyShellFromShellPath } from '../../common/terminal/shellDetectors/baseShellDetector'; -import { TerminalShellType } from '../../common/terminal/types'; -import { sendTelemetryEvent } from '../../telemetry'; -import { EventName } from '../../telemetry/constants'; - -export const terminalDeactivationPromptKey = 'TERMINAL_DEACTIVATION_PROMPT_KEY'; - -@injectable() -export class TerminalDeactivateLimitationPrompt implements IExtensionSingleActivationService { - public readonly supportedWorkspaceTypes = { untrustedWorkspace: false, virtualWorkspace: false }; - - constructor( - @inject(IApplicationShell) private readonly appShell: IApplicationShell, - @inject(IPersistentStateFactory) private readonly persistentStateFactory: IPersistentStateFactory, - @inject(IDisposableRegistry) private readonly disposableRegistry: IDisposableRegistry, - @inject(IInterpreterService) private readonly interpreterService: IInterpreterService, - @inject(IBrowserService) private readonly browserService: IBrowserService, - @inject(IApplicationEnvironment) private readonly appEnvironment: IApplicationEnvironment, - @inject(IExperimentService) private readonly experimentService: IExperimentService, - ) {} - - public async activate(): Promise { - if (!inTerminalEnvVarExperiment(this.experimentService)) { - return; - } - this.disposableRegistry.push( - this.appShell.onDidWriteTerminalData(async (e) => { - if (!e.data.includes('deactivate')) { - return; - } - const shellType = identifyShellFromShellPath(this.appEnvironment.shell); - if (shellType === TerminalShellType.commandPrompt) { - return; - } - const { terminal } = e; - const cwd = - 'cwd' in terminal.creationOptions && terminal.creationOptions.cwd - ? terminal.creationOptions.cwd - : undefined; - const resource = typeof cwd === 'string' ? Uri.file(cwd) : cwd; - const interpreter = await this.interpreterService.getActiveInterpreter(resource); - if (interpreter?.type !== PythonEnvType.Virtual) { - return; - } - await this.notifyUsers(); - }), - ); - } - - private async notifyUsers(): Promise { - const notificationPromptEnabled = this.persistentStateFactory.createGlobalPersistentState( - terminalDeactivationPromptKey, - true, - ); - if (!notificationPromptEnabled.value) { - return; - } - const prompts = [Common.seeInstructions, Interpreters.deactivateDoneButton, Common.doNotShowAgain]; - const telemetrySelections: ['See Instructions', 'Done, it works', "Don't show again"] = [ - 'See Instructions', - 'Done, it works', - "Don't show again", - ]; - const selection = await this.appShell.showWarningMessage(Interpreters.terminalDeactivatePrompt, ...prompts); - if (!selection) { - return; - } - sendTelemetryEvent(EventName.TERMINAL_DEACTIVATE_PROMPT, undefined, { - selection: selection ? telemetrySelections[prompts.indexOf(selection)] : undefined, - }); - if (selection === prompts[0]) { - const url = `https://aka.ms/AAmx2ft`; - this.browserService.launch(url); - } - if (selection === prompts[1] || selection === prompts[2]) { - await notificationPromptEnabled.updateValue(false); - } - } -} diff --git a/src/client/terminals/serviceRegistry.ts b/src/client/terminals/serviceRegistry.ts index a9da776d011a..a39ef31a8fe4 100644 --- a/src/client/terminals/serviceRegistry.ts +++ b/src/client/terminals/serviceRegistry.ts @@ -1,26 +1,25 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { IServiceManager } from '../ioc/types'; +import { interfaces } from 'inversify'; +import { ClassType } from '../ioc/types'; import { TerminalAutoActivation } from './activation'; import { CodeExecutionManager } from './codeExecution/codeExecutionManager'; import { DjangoShellCodeExecutionProvider } from './codeExecution/djangoShellCodeExecution'; import { CodeExecutionHelper } from './codeExecution/helper'; import { ReplProvider } from './codeExecution/repl'; import { TerminalCodeExecutionProvider } from './codeExecution/terminalCodeExecution'; -import { - ICodeExecutionHelper, - ICodeExecutionManager, - ICodeExecutionService, - ITerminalAutoActivation, - ITerminalEnvVarCollectionService, -} from './types'; -import { TerminalEnvVarCollectionService } from './envCollectionActivation/service'; -import { IExtensionActivationService, IExtensionSingleActivationService } from '../activation/types'; -import { TerminalDeactivateLimitationPrompt } from './envCollectionActivation/deactivatePrompt'; -import { TerminalIndicatorPrompt } from './envCollectionActivation/indicatorPrompt'; +import { ICodeExecutionHelper, ICodeExecutionManager, ICodeExecutionService, ITerminalAutoActivation } from './types'; -export function registerTypes(serviceManager: IServiceManager): void { +interface IServiceRegistry { + addSingleton( + serviceIdentifier: interfaces.ServiceIdentifier, + constructor: ClassType, + name?: string | number | symbol, + ): void; +} + +export function registerTypes(serviceManager: IServiceRegistry): void { serviceManager.addSingleton(ICodeExecutionHelper, CodeExecutionHelper); serviceManager.addSingleton(ICodeExecutionManager, CodeExecutionManager); @@ -38,17 +37,4 @@ export function registerTypes(serviceManager: IServiceManager): void { serviceManager.addSingleton(ICodeExecutionService, ReplProvider, 'repl'); serviceManager.addSingleton(ITerminalAutoActivation, TerminalAutoActivation); - serviceManager.addSingleton( - ITerminalEnvVarCollectionService, - TerminalEnvVarCollectionService, - ); - serviceManager.addSingleton( - IExtensionSingleActivationService, - TerminalIndicatorPrompt, - ); - serviceManager.addSingleton( - IExtensionSingleActivationService, - TerminalDeactivateLimitationPrompt, - ); - serviceManager.addBinding(ITerminalEnvVarCollectionService, IExtensionActivationService); } diff --git a/src/client/terminals/types.ts b/src/client/terminals/types.ts index 48d60adf3f39..47ac16d9e08b 100644 --- a/src/client/terminals/types.ts +++ b/src/client/terminals/types.ts @@ -33,11 +33,3 @@ export interface ITerminalAutoActivation extends IDisposable { register(): void; disableAutoActivation(terminal: Terminal): void; } - -export const ITerminalEnvVarCollectionService = Symbol('ITerminalEnvVarCollectionService'); -export interface ITerminalEnvVarCollectionService { - /** - * Returns true if we know with high certainity the terminal prompt is set correctly for a particular resource. - */ - isTerminalPromptSetCorrectly(resource?: Resource): boolean; -} diff --git a/src/test/interpreters/activation/terminalEnvVarCollectionPrompt.unit.test.ts b/src/test/interpreters/activation/terminalEnvVarCollectionPrompt.unit.test.ts index 5d4da49ebb45..baa83c8b11c5 100644 --- a/src/test/interpreters/activation/terminalEnvVarCollectionPrompt.unit.test.ts +++ b/src/test/interpreters/activation/terminalEnvVarCollectionPrompt.unit.test.ts @@ -13,13 +13,13 @@ import { IPersistentStateFactory, IPythonSettings, } from '../../../client/common/types'; -import { TerminalIndicatorPrompt } from '../../../client/terminals/envCollectionActivation/indicatorPrompt'; +import { TerminalEnvVarCollectionPrompt } from '../../../client/interpreter/activation/terminalEnvVarCollectionPrompt'; +import { ITerminalEnvVarCollectionService } from '../../../client/interpreter/activation/types'; import { Common, Interpreters } from '../../../client/common/utils/localize'; import { TerminalEnvVarActivation } from '../../../client/common/experiments/groups'; import { sleep } from '../../core'; import { IInterpreterService } from '../../../client/interpreter/contracts'; import { PythonEnvironment } from '../../../client/pythonEnvironments/info'; -import { ITerminalEnvVarCollectionService } from '../../../client/terminals/types'; suite('Terminal Environment Variable Collection Prompt', () => { let shell: IApplicationShell; @@ -28,7 +28,7 @@ suite('Terminal Environment Variable Collection Prompt', () => { let activeResourceService: IActiveResourceService; let terminalEnvVarCollectionService: ITerminalEnvVarCollectionService; let persistentStateFactory: IPersistentStateFactory; - let terminalEnvVarCollectionPrompt: TerminalIndicatorPrompt; + let terminalEnvVarCollectionPrompt: TerminalEnvVarCollectionPrompt; let terminalEventEmitter: EventEmitter; let notificationEnabled: IPersistentState; let configurationService: IConfigurationService; @@ -61,7 +61,7 @@ suite('Terminal Environment Variable Collection Prompt', () => { ); when(experimentService.inExperimentSync(TerminalEnvVarActivation.experiment)).thenReturn(true); when(terminalManager.onDidOpenTerminal).thenReturn(terminalEventEmitter.event); - terminalEnvVarCollectionPrompt = new TerminalIndicatorPrompt( + terminalEnvVarCollectionPrompt = new TerminalEnvVarCollectionPrompt( instance(shell), instance(persistentStateFactory), instance(terminalManager), diff --git a/src/test/interpreters/activation/terminalEnvVarCollectionService.unit.test.ts b/src/test/interpreters/activation/terminalEnvVarCollectionService.unit.test.ts index 5e572e7ad06f..e41d6ce4d53c 100644 --- a/src/test/interpreters/activation/terminalEnvVarCollectionService.unit.test.ts +++ b/src/test/interpreters/activation/terminalEnvVarCollectionService.unit.test.ts @@ -32,7 +32,7 @@ import { import { Interpreters } from '../../../client/common/utils/localize'; import { OSType, getOSType } from '../../../client/common/utils/platform'; import { defaultShells } from '../../../client/interpreter/activation/service'; -import { TerminalEnvVarCollectionService } from '../../../client/terminals/envCollectionActivation/service'; +import { TerminalEnvVarCollectionService } from '../../../client/interpreter/activation/terminalEnvVarCollectionService'; import { IEnvironmentActivationService } from '../../../client/interpreter/activation/types'; import { IInterpreterService } from '../../../client/interpreter/contracts'; import { PathUtils } from '../../../client/common/platform/pathUtils'; diff --git a/src/test/terminals/envCollectionActivation/deactivatePrompt.unit.test.ts b/src/test/terminals/envCollectionActivation/deactivatePrompt.unit.test.ts deleted file mode 100644 index acd8ee99e5d7..000000000000 --- a/src/test/terminals/envCollectionActivation/deactivatePrompt.unit.test.ts +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { mock, when, anything, instance, verify, reset } from 'ts-mockito'; -import { EventEmitter, Terminal, TerminalDataWriteEvent, Uri } from 'vscode'; -import { IApplicationEnvironment, IApplicationShell } from '../../../client/common/application/types'; -import { - IBrowserService, - IExperimentService, - IPersistentState, - IPersistentStateFactory, -} from '../../../client/common/types'; -import { Common, Interpreters } from '../../../client/common/utils/localize'; -import { TerminalEnvVarActivation } from '../../../client/common/experiments/groups'; -import { sleep } from '../../core'; -import { IInterpreterService } from '../../../client/interpreter/contracts'; -import { PythonEnvironment } from '../../../client/pythonEnvironments/info'; -import { TerminalDeactivateLimitationPrompt } from '../../../client/terminals/envCollectionActivation/deactivatePrompt'; -import { PythonEnvType } from '../../../client/pythonEnvironments/base/info'; -import { TerminalShellType } from '../../../client/common/terminal/types'; - -suite('Terminal Deactivation Limitation Prompt', () => { - let shell: IApplicationShell; - let experimentService: IExperimentService; - let persistentStateFactory: IPersistentStateFactory; - let appEnvironment: IApplicationEnvironment; - let deactivatePrompt: TerminalDeactivateLimitationPrompt; - let terminalWriteEvent: EventEmitter; - let notificationEnabled: IPersistentState; - let browserService: IBrowserService; - let interpreterService: IInterpreterService; - const prompts = [Common.seeInstructions, Interpreters.deactivateDoneButton, Common.doNotShowAgain]; - const expectedMessage = Interpreters.terminalDeactivatePrompt; - - setup(async () => { - shell = mock(); - interpreterService = mock(); - experimentService = mock(); - persistentStateFactory = mock(); - appEnvironment = mock(); - when(appEnvironment.shell).thenReturn('bash'); - browserService = mock(); - notificationEnabled = mock>(); - terminalWriteEvent = new EventEmitter(); - when(persistentStateFactory.createGlobalPersistentState(anything(), true)).thenReturn( - instance(notificationEnabled), - ); - when(shell.onDidWriteTerminalData).thenReturn(terminalWriteEvent.event); - when(experimentService.inExperimentSync(TerminalEnvVarActivation.experiment)).thenReturn(true); - deactivatePrompt = new TerminalDeactivateLimitationPrompt( - instance(shell), - instance(persistentStateFactory), - [], - instance(interpreterService), - instance(browserService), - instance(appEnvironment), - instance(experimentService), - ); - }); - - test('Show notification when "deactivate" command is run when a virtual env is selected', async () => { - const resource = Uri.file('a'); - const terminal = ({ - creationOptions: { - cwd: resource, - }, - } as unknown) as Terminal; - when(notificationEnabled.value).thenReturn(true); - when(interpreterService.getActiveInterpreter(anything())).thenResolve(({ - type: PythonEnvType.Virtual, - } as unknown) as PythonEnvironment); - when(shell.showWarningMessage(expectedMessage, ...prompts)).thenResolve(undefined); - - await deactivatePrompt.activate(); - terminalWriteEvent.fire({ data: 'Please deactivate me', terminal }); - await sleep(1); - - verify(shell.showWarningMessage(expectedMessage, ...prompts)).once(); - }); - - test('When using cmd, do not show notification for the same', async () => { - const resource = Uri.file('a'); - const terminal = ({ - creationOptions: { - cwd: resource, - }, - } as unknown) as Terminal; - reset(appEnvironment); - when(appEnvironment.shell).thenReturn(TerminalShellType.commandPrompt); - when(notificationEnabled.value).thenReturn(true); - when(interpreterService.getActiveInterpreter(anything())).thenResolve(({ - type: PythonEnvType.Virtual, - } as unknown) as PythonEnvironment); - when(shell.showWarningMessage(expectedMessage, ...prompts)).thenResolve(undefined); - - await deactivatePrompt.activate(); - terminalWriteEvent.fire({ data: 'Please deactivate me', terminal }); - await sleep(1); - - verify(shell.showWarningMessage(expectedMessage, ...prompts)).once(); - }); - - test('When not in experiment, do not show notification for the same', async () => { - reset(experimentService); - when(experimentService.inExperimentSync(TerminalEnvVarActivation.experiment)).thenReturn(false); - const resource = Uri.file('a'); - const terminal = ({ - creationOptions: { - cwd: resource, - }, - } as unknown) as Terminal; - when(notificationEnabled.value).thenReturn(true); - when(interpreterService.getActiveInterpreter(anything())).thenResolve(({ - type: PythonEnvType.Virtual, - } as unknown) as PythonEnvironment); - when(shell.showWarningMessage(expectedMessage, ...prompts)).thenResolve(undefined); - - await deactivatePrompt.activate(); - terminalWriteEvent.fire({ data: 'Please deactivate me', terminal }); - await sleep(1); - - verify(shell.showWarningMessage(expectedMessage, ...prompts)).never(); - }); - - test('Do not show notification if notification is disabled', async () => { - const resource = Uri.file('a'); - const terminal = ({ - creationOptions: { - cwd: resource, - }, - } as unknown) as Terminal; - when(notificationEnabled.value).thenReturn(false); - when(interpreterService.getActiveInterpreter(anything())).thenResolve(({ - type: PythonEnvType.Virtual, - } as unknown) as PythonEnvironment); - when(shell.showWarningMessage(expectedMessage, ...prompts)).thenResolve(undefined); - - await deactivatePrompt.activate(); - terminalWriteEvent.fire({ data: 'Please deactivate me', terminal }); - await sleep(1); - - verify(shell.showWarningMessage(expectedMessage, ...prompts)).never(); - }); - - test('Do not show notification when virtual env is not activated for terminal', async () => { - const resource = Uri.file('a'); - const terminal = ({ - creationOptions: { - cwd: resource, - }, - } as unknown) as Terminal; - when(notificationEnabled.value).thenReturn(true); - when(interpreterService.getActiveInterpreter(anything())).thenResolve(({ - type: PythonEnvType.Conda, - } as unknown) as PythonEnvironment); - when(shell.showWarningMessage(expectedMessage, ...prompts)).thenResolve(undefined); - - await deactivatePrompt.activate(); - terminalWriteEvent.fire({ data: 'Please deactivate me', terminal }); - await sleep(1); - - verify(shell.showWarningMessage(expectedMessage, ...prompts)).never(); - }); - - test("Disable notification if `Don't show again` is clicked", async () => { - const resource = Uri.file('a'); - const terminal = ({ - creationOptions: { - cwd: resource, - }, - } as unknown) as Terminal; - when(notificationEnabled.value).thenReturn(true); - when(interpreterService.getActiveInterpreter(anything())).thenResolve(({ - type: PythonEnvType.Virtual, - } as unknown) as PythonEnvironment); - when(shell.showWarningMessage(expectedMessage, ...prompts)).thenReturn(Promise.resolve(Common.doNotShowAgain)); - - await deactivatePrompt.activate(); - terminalWriteEvent.fire({ data: 'Please deactivate me', terminal }); - await sleep(1); - - verify(notificationEnabled.updateValue(false)).once(); - }); - - test('Disable notification if `Done, it works` is clicked', async () => { - const resource = Uri.file('a'); - const terminal = ({ - creationOptions: { - cwd: resource, - }, - } as unknown) as Terminal; - when(notificationEnabled.value).thenReturn(true); - when(interpreterService.getActiveInterpreter(anything())).thenResolve(({ - type: PythonEnvType.Virtual, - } as unknown) as PythonEnvironment); - when(shell.showWarningMessage(expectedMessage, ...prompts)).thenReturn( - Promise.resolve(Interpreters.deactivateDoneButton), - ); - - await deactivatePrompt.activate(); - terminalWriteEvent.fire({ data: 'Please deactivate me', terminal }); - await sleep(1); - - verify(notificationEnabled.updateValue(false)).once(); - }); - - test('Open link to workaround if `See instructions` is clicked', async () => { - const resource = Uri.file('a'); - const terminal = ({ - creationOptions: { - cwd: resource, - }, - } as unknown) as Terminal; - when(notificationEnabled.value).thenReturn(true); - when(interpreterService.getActiveInterpreter(anything())).thenResolve(({ - type: PythonEnvType.Virtual, - } as unknown) as PythonEnvironment); - when(shell.showWarningMessage(expectedMessage, ...prompts)).thenReturn(Promise.resolve(Common.seeInstructions)); - - await deactivatePrompt.activate(); - terminalWriteEvent.fire({ data: 'Please deactivate me', terminal }); - await sleep(1); - - verify(shell.showWarningMessage(expectedMessage, ...prompts)).once(); - verify(browserService.launch(anything())).once(); - }); - - test('Do not perform any action if prompt is closed', async () => { - const resource = Uri.file('a'); - const terminal = ({ - creationOptions: { - cwd: resource, - }, - } as unknown) as Terminal; - when(notificationEnabled.value).thenReturn(true); - when(interpreterService.getActiveInterpreter(anything())).thenResolve(({ - type: PythonEnvType.Virtual, - } as unknown) as PythonEnvironment); - when(shell.showWarningMessage(expectedMessage, ...prompts)).thenResolve(undefined); - - await deactivatePrompt.activate(); - terminalWriteEvent.fire({ data: 'Please deactivate me', terminal }); - await sleep(1); - - verify(shell.showWarningMessage(expectedMessage, ...prompts)).once(); - verify(notificationEnabled.updateValue(false)).never(); - verify(browserService.launch(anything())).never(); - }); -}); diff --git a/src/test/terminals/serviceRegistry.unit.test.ts b/src/test/terminals/serviceRegistry.unit.test.ts index 816afa17cf88..38a9a9744e91 100644 --- a/src/test/terminals/serviceRegistry.unit.test.ts +++ b/src/test/terminals/serviceRegistry.unit.test.ts @@ -2,7 +2,6 @@ // Licensed under the MIT License. import * as typemoq from 'typemoq'; -import { IExtensionActivationService, IExtensionSingleActivationService } from '../../client/activation/types'; import { IServiceManager } from '../../client/ioc/types'; import { TerminalAutoActivation } from '../../client/terminals/activation'; import { CodeExecutionManager } from '../../client/terminals/codeExecution/codeExecutionManager'; @@ -10,16 +9,12 @@ import { DjangoShellCodeExecutionProvider } from '../../client/terminals/codeExe import { CodeExecutionHelper } from '../../client/terminals/codeExecution/helper'; import { ReplProvider } from '../../client/terminals/codeExecution/repl'; import { TerminalCodeExecutionProvider } from '../../client/terminals/codeExecution/terminalCodeExecution'; -import { TerminalDeactivateLimitationPrompt } from '../../client/terminals/envCollectionActivation/deactivatePrompt'; -import { TerminalIndicatorPrompt } from '../../client/terminals/envCollectionActivation/indicatorPrompt'; -import { TerminalEnvVarCollectionService } from '../../client/terminals/envCollectionActivation/service'; import { registerTypes } from '../../client/terminals/serviceRegistry'; import { ICodeExecutionHelper, ICodeExecutionManager, ICodeExecutionService, ITerminalAutoActivation, - ITerminalEnvVarCollectionService, } from '../../client/terminals/types'; suite('Terminal - Service Registry', () => { @@ -32,9 +27,6 @@ suite('Terminal - Service Registry', () => { [ICodeExecutionService, ReplProvider, 'repl'], [ITerminalAutoActivation, TerminalAutoActivation], [ICodeExecutionService, TerminalCodeExecutionProvider, 'standard'], - [ITerminalEnvVarCollectionService, TerminalEnvVarCollectionService], - [IExtensionSingleActivationService, TerminalIndicatorPrompt], - [IExtensionSingleActivationService, TerminalDeactivateLimitationPrompt], ].forEach((args) => { if (args.length === 2) { services @@ -58,14 +50,6 @@ suite('Terminal - Service Registry', () => { .verifiable(typemoq.Times.once()); } }); - services - .setup((s) => - s.addBinding( - typemoq.It.is((v) => ITerminalEnvVarCollectionService === v), - typemoq.It.is((value) => IExtensionActivationService === value), - ), - ) - .verifiable(typemoq.Times.once()); registerTypes(services.object); diff --git a/typings/vscode-proposed/vscode.proposed.terminalDataWriteEvent.d.ts b/typings/vscode-proposed/vscode.proposed.terminalDataWriteEvent.d.ts deleted file mode 100644 index 6913b862c70f..000000000000 --- a/typings/vscode-proposed/vscode.proposed.terminalDataWriteEvent.d.ts +++ /dev/null @@ -1,31 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -declare module 'vscode' { - // https://github.com/microsoft/vscode/issues/78502 - // - // This API is still proposed but we don't intent on promoting it to stable due to problems - // around performance. See #145234 for a more likely API to get stabilized. - - export interface TerminalDataWriteEvent { - /** - * The {@link Terminal} for which the data was written. - */ - readonly terminal: Terminal; - /** - * The data being written. - */ - readonly data: string; - } - - namespace window { - /** - * An event which fires when the terminal's child pseudo-device is written to (the shell). - * In other words, this provides access to the raw data stream from the process running - * within the terminal, including VT sequences. - */ - export const onDidWriteTerminalData: Event; - } -}