Skip to content

Commit 5a19bbb

Browse files
committed
Co-authored-by: Daniel Imms <[email protected]>
1 parent 6578d9d commit 5a19bbb

File tree

10 files changed

+93
-22
lines changed

10 files changed

+93
-22
lines changed

.eslintrc

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"@typescript-eslint/no-dupe-class-members": "error",
2929
"no-empty-function": "off",
3030
"@typescript-eslint/no-empty-function": ["error"],
31+
"no-inner-declarations": "warn",
3132
"@typescript-eslint/no-empty-interface": "off",
3233
"@typescript-eslint/no-explicit-any": "error",
3334
"@typescript-eslint/no-non-null-assertion": "off",

src/client/common/terminal/service.ts

+5
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export class TerminalService implements ITerminalService, Disposable {
3939
@inject(IServiceContainer) private serviceContainer: IServiceContainer,
4040
private readonly options?: TerminalCreationOptions,
4141
) {
42+
const a: TerminalService;
4243
const disposableRegistry = this.serviceContainer.get<Disposable[]>(IDisposableRegistry);
4344
disposableRegistry.push(this);
4445
this.terminalHelper = this.serviceContainer.get<ITerminalHelper>(ITerminalHelper);
@@ -74,6 +75,10 @@ export class TerminalService implements ITerminalService, Disposable {
7475
this.terminal!.show(preserveFocus);
7576
}
7677
}
78+
// When terminal is launched
79+
// Copy pythonrc into <userdata>/pythonrc.py
80+
// Update environment variable collection to include PYTHONSTARTUP=<userdata>/pythonrc.py
81+
7782
public async ensureTerminal(preserveFocus: boolean = true): Promise<void> {
7883
if (this.terminal) {
7984
return;

src/client/extensionActivation.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,12 @@ import { TerminalProvider } from './providers/terminalProvider';
3232
import { setExtensionInstallTelemetryProperties } from './telemetry/extensionInstallTelemetry';
3333
import { registerTypes as tensorBoardRegisterTypes } from './tensorBoard/serviceRegistry';
3434
import { registerTypes as commonRegisterTerminalTypes } from './terminals/serviceRegistry';
35-
import { ICodeExecutionHelper, ICodeExecutionManager, ITerminalAutoActivation } from './terminals/types';
35+
import {
36+
ICodeExecutionHelper,
37+
ICodeExecutionManager,
38+
IPythonStartupEnvVarService,
39+
ITerminalAutoActivation,
40+
} from './terminals/types';
3641
import { registerTypes as unitTestsRegisterTypes } from './testing/serviceRegistry';
3742

3843
// components
@@ -176,6 +181,7 @@ async function activateLegacy(ext: ExtensionState, startupStopWatch: StopWatch):
176181
serviceContainer.get<IApplicationDiagnostics>(IApplicationDiagnostics).register();
177182

178183
serviceManager.get<ITerminalAutoActivation>(ITerminalAutoActivation).register();
184+
serviceManager.get<IPythonStartupEnvVarService>(IPythonStartupEnvVarService).register();
179185

180186
serviceManager.get<ICodeExecutionManager>(ICodeExecutionManager).registerCommands();
181187

src/client/terminals/envCollectionActivation/service.ts

+21-8
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
EnvironmentVariableScope,
1111
EnvironmentVariableMutatorOptions,
1212
ProgressLocation,
13+
EnvironmentVariableCollection,
1314
} from 'vscode';
1415
import { pathExists, normCase } from '../../common/platform/fs-paths';
1516
import { IExtensionActivationService } from '../../activation/types';
@@ -37,7 +38,11 @@ import { TerminalShellType } from '../../common/terminal/types';
3738
import { OSType } from '../../common/utils/platform';
3839

3940
import { PythonEnvType } from '../../pythonEnvironments/base/info';
40-
import { IShellIntegrationService, ITerminalDeactivateService, ITerminalEnvVarCollectionService } from '../types';
41+
import {
42+
IShellIntegrationDetectionService,
43+
ITerminalDeactivateService,
44+
ITerminalEnvVarCollectionService,
45+
} from '../types';
4146
import { ProgressService } from '../../common/application/progressService';
4247

4348
@injectable()
@@ -80,7 +85,8 @@ export class TerminalEnvVarCollectionService implements IExtensionActivationServ
8085
@inject(IConfigurationService) private readonly configurationService: IConfigurationService,
8186
@inject(ITerminalDeactivateService) private readonly terminalDeactivateService: ITerminalDeactivateService,
8287
@inject(IPathUtils) private readonly pathUtils: IPathUtils,
83-
@inject(IShellIntegrationService) private readonly shellIntegrationService: IShellIntegrationService,
88+
@inject(IShellIntegrationDetectionService)
89+
private readonly shellIntegrationService: IShellIntegrationDetectionService,
8490
@inject(IEnvironmentVariablesProvider)
8591
private readonly environmentVariablesProvider: IEnvironmentVariablesProvider,
8692
) {
@@ -91,7 +97,8 @@ export class TerminalEnvVarCollectionService implements IExtensionActivationServ
9197
public async activate(resource: Resource): Promise<void> {
9298
try {
9399
if (!inTerminalEnvVarExperiment(this.experimentService)) {
94-
this.context.environmentVariableCollection.clear();
100+
clearCollectionVariables(this.context.environmentVariableCollection);
101+
95102
await this.handleMicroVenv(resource);
96103
if (!this.registeredOnce) {
97104
this.interpreterService.onDidChangeInterpreter(
@@ -171,7 +178,7 @@ export class TerminalEnvVarCollectionService implements IExtensionActivationServ
171178
const settings = this.configurationService.getSettings(resource);
172179
const envVarCollection = this.getEnvironmentVariableCollection({ workspaceFolder });
173180
if (!settings.terminal.activateEnvironment) {
174-
envVarCollection.clear();
181+
clearCollectionVariables(envVarCollection);
175182
traceVerbose('Activating environments in terminal is disabled for', resource?.fsPath);
176183
return;
177184
}
@@ -193,7 +200,7 @@ export class TerminalEnvVarCollectionService implements IExtensionActivationServ
193200
return;
194201
}
195202
await this.trackTerminalPrompt(shell, resource, env);
196-
envVarCollection.clear();
203+
clearCollectionVariables(envVarCollection);
197204
this.processEnvVars = undefined;
198205
return;
199206
}
@@ -210,7 +217,7 @@ export class TerminalEnvVarCollectionService implements IExtensionActivationServ
210217
const defaultPrependOptions = await this.getPrependOptions();
211218

212219
// Clear any previously set env vars from collection
213-
envVarCollection.clear();
220+
clearCollectionVariables(envVarCollection);
214221
const deactivate = await this.terminalDeactivateService.getScriptLocation(shell, resource);
215222
Object.keys(env).forEach((key) => {
216223
if (shouldSkip(key)) {
@@ -367,7 +374,7 @@ export class TerminalEnvVarCollectionService implements IExtensionActivationServ
367374
const settings = this.configurationService.getSettings(resource);
368375
const workspaceFolder = this.getWorkspaceFolder(resource);
369376
if (!settings.terminal.activateEnvironment) {
370-
this.getEnvironmentVariableCollection({ workspaceFolder }).clear();
377+
clearCollectionVariables(this.getEnvironmentVariableCollection({ workspaceFolder }));
371378
traceVerbose(
372379
'Do not activate microvenv as activating environments in terminal is disabled for',
373380
resource?.fsPath,
@@ -387,7 +394,7 @@ export class TerminalEnvVarCollectionService implements IExtensionActivationServ
387394
);
388395
return;
389396
}
390-
this.getEnvironmentVariableCollection({ workspaceFolder }).clear();
397+
clearCollectionVariables(this.getEnvironmentVariableCollection({ workspaceFolder }));
391398
}
392399
} catch (ex) {
393400
traceWarn(`Microvenv failed as it is using proposed API which is constantly changing`, ex);
@@ -485,3 +492,9 @@ function normCaseKeys(env: EnvironmentVariables): EnvironmentVariables {
485492
});
486493
return result;
487494
}
495+
496+
function clearCollectionVariables(collection: EnvironmentVariableCollection) {
497+
for (const key of ['PS1', 'PATH']) {
498+
collection.delete(key);
499+
}
500+
}

src/client/terminals/envCollectionActivation/shellIntegrationService.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { TerminalShellType } from '../../common/terminal/types';
1414
import { IDisposableRegistry, IPersistentStateFactory } from '../../common/types';
1515
import { sleep } from '../../common/utils/async';
1616
import { traceError, traceVerbose } from '../../logging';
17-
import { IShellIntegrationService } from '../types';
17+
import { IShellIntegrationDetectionService } from '../types';
1818

1919
/**
2020
* This is a list of shells which support shell integration:
@@ -33,7 +33,7 @@ export enum isShellIntegrationWorking {
3333
}
3434

3535
@injectable()
36-
export class ShellIntegrationService implements IShellIntegrationService {
36+
export class ShellIntegrationDetectionService implements IShellIntegrationDetectionService {
3737
private isWorkingForShell = new Set<TerminalShellType>();
3838

3939
private readonly didChange = new EventEmitter<void>();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
import * as path from 'path';
5+
import { injectable, inject } from 'inversify';
6+
import { Uri, workspace } from 'vscode';
7+
import { IPythonStartupEnvVarService } from '../types';
8+
import { IExtensionContext } from '../../common/types';
9+
import { EXTENSION_ROOT_DIR } from '../../constants';
10+
11+
@injectable()
12+
export class PythonStartupEnvVarService implements IPythonStartupEnvVarService {
13+
constructor(@inject(IExtensionContext) private context: IExtensionContext) {}
14+
15+
public async register(): Promise<void> {
16+
const storageUri = this.context.storageUri || this.context.globalStorageUri;
17+
try {
18+
await workspace.fs.createDirectory(storageUri);
19+
} catch {
20+
// already exists, most likely
21+
}
22+
const destPath = Uri.joinPath(storageUri, 'pythonrc.py');
23+
24+
// TODO: Only do this when we have a setting
25+
// Rollout strategy:
26+
// Stage 1. Opt-in setting in stable/insiders
27+
// Stage 2. Out-out setting in insiders
28+
// Stage 3. Out-out setting in stable (or experiment?)
29+
const sourcePath = path.join(EXTENSION_ROOT_DIR, 'python_files', 'pythonrc.py');
30+
31+
await workspace.fs.copy(Uri.file(sourcePath), destPath, { overwrite: true });
32+
33+
this.context.environmentVariableCollection.replace('PYTHONSTARTUP', destPath.fsPath);
34+
}
35+
}

src/client/terminals/serviceRegistry.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,18 @@ import {
1212
ICodeExecutionHelper,
1313
ICodeExecutionManager,
1414
ICodeExecutionService,
15-
IShellIntegrationService,
15+
IPythonStartupEnvVarService,
16+
IShellIntegrationDetectionService,
1617
ITerminalAutoActivation,
1718
ITerminalDeactivateService,
1819
ITerminalEnvVarCollectionService,
1920
} from './types';
2021
import { TerminalEnvVarCollectionService } from './envCollectionActivation/service';
2122
import { IExtensionActivationService, IExtensionSingleActivationService } from '../activation/types';
2223
import { TerminalIndicatorPrompt } from './envCollectionActivation/indicatorPrompt';
23-
import { ShellIntegrationService } from './envCollectionActivation/shellIntegrationService';
24+
import { ShellIntegrationDetectionService } from './envCollectionActivation/shellIntegrationService';
2425
import { TerminalDeactivateService } from './envCollectionActivation/deactivateService';
26+
import { PythonStartupEnvVarService } from './pythonstartupEnvVar/service';
2527

2628
export function registerTypes(serviceManager: IServiceManager): void {
2729
serviceManager.addSingleton<ICodeExecutionHelper>(ICodeExecutionHelper, CodeExecutionHelper);
@@ -50,6 +52,10 @@ export function registerTypes(serviceManager: IServiceManager): void {
5052
IExtensionSingleActivationService,
5153
TerminalIndicatorPrompt,
5254
);
53-
serviceManager.addSingleton<IShellIntegrationService>(IShellIntegrationService, ShellIntegrationService);
55+
serviceManager.addSingleton<IShellIntegrationDetectionService>(
56+
IShellIntegrationDetectionService,
57+
ShellIntegrationDetectionService,
58+
);
59+
serviceManager.addSingleton<IPythonStartupEnvVarService>(IPythonStartupEnvVarService, PythonStartupEnvVarService);
5460
serviceManager.addBinding(ITerminalEnvVarCollectionService, IExtensionActivationService);
5561
}

src/client/terminals/types.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ export interface ITerminalEnvVarCollectionService {
4242
isTerminalPromptSetCorrectly(resource?: Resource): boolean;
4343
}
4444

45-
export const IShellIntegrationService = Symbol('IShellIntegrationService');
46-
export interface IShellIntegrationService {
45+
export const IShellIntegrationDetectionService = Symbol('IShellIntegrationDetectionService');
46+
export interface IShellIntegrationDetectionService {
4747
onDidChangeStatus: Event<void>;
4848
isWorking(): Promise<boolean>;
4949
}
@@ -53,3 +53,8 @@ export interface ITerminalDeactivateService {
5353
initializeScriptParams(shell: string): Promise<void>;
5454
getScriptLocation(shell: string, resource: Resource): Promise<string | undefined>;
5555
}
56+
57+
export const IPythonStartupEnvVarService = Symbol('IPythonStartupEnvVarService');
58+
export interface IPythonStartupEnvVarService {
59+
register(): void;
60+
}

src/test/interpreters/activation/terminalEnvVarCollectionService.unit.test.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import { IInterpreterService } from '../../../client/interpreter/contracts';
3737
import { PathUtils } from '../../../client/common/platform/pathUtils';
3838
import { PythonEnvType } from '../../../client/pythonEnvironments/base/info';
3939
import { PythonEnvironment } from '../../../client/pythonEnvironments/info';
40-
import { IShellIntegrationService, ITerminalDeactivateService } from '../../../client/terminals/types';
40+
import { IShellIntegrationDetectionService, ITerminalDeactivateService } from '../../../client/terminals/types';
4141
import { IEnvironmentVariablesProvider } from '../../../client/common/variables/types';
4242

4343
suite('Terminal Environment Variable Collection Service', () => {
@@ -58,7 +58,7 @@ suite('Terminal Environment Variable Collection Service', () => {
5858
title: Interpreters.activatingTerminals,
5959
};
6060
let configService: IConfigurationService;
61-
let shellIntegrationService: IShellIntegrationService;
61+
let shellIntegrationService: IShellIntegrationDetectionService;
6262
const displayPath = 'display/path';
6363
const customShell = 'powershell';
6464
const defaultShell = defaultShells[getOSType()];
@@ -76,7 +76,7 @@ suite('Terminal Environment Variable Collection Service', () => {
7676
context = mock<IExtensionContext>();
7777
shell = mock<IApplicationShell>();
7878
const envVarProvider = mock<IEnvironmentVariablesProvider>();
79-
shellIntegrationService = mock<IShellIntegrationService>();
79+
shellIntegrationService = mock<IShellIntegrationDetectionService>();
8080
when(shellIntegrationService.isWorking()).thenResolve(true);
8181
globalCollection = mock<GlobalEnvironmentVariableCollection>();
8282
collection = mock<EnvironmentVariableCollection>();

src/test/terminals/serviceRegistry.unit.test.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ import { TerminalCodeExecutionProvider } from '../../client/terminals/codeExecut
1414
import { TerminalDeactivateService } from '../../client/terminals/envCollectionActivation/deactivateService';
1515
import { TerminalIndicatorPrompt } from '../../client/terminals/envCollectionActivation/indicatorPrompt';
1616
import { TerminalEnvVarCollectionService } from '../../client/terminals/envCollectionActivation/service';
17-
import { ShellIntegrationService } from '../../client/terminals/envCollectionActivation/shellIntegrationService';
17+
import { ShellIntegrationDetectionService } from '../../client/terminals/envCollectionActivation/shellIntegrationService';
1818
import { registerTypes } from '../../client/terminals/serviceRegistry';
1919
import {
2020
ICodeExecutionHelper,
2121
ICodeExecutionManager,
2222
ICodeExecutionService,
23-
IShellIntegrationService,
23+
IShellIntegrationDetectionService,
2424
ITerminalAutoActivation,
2525
ITerminalDeactivateService,
2626
ITerminalEnvVarCollectionService,
@@ -39,7 +39,7 @@ suite('Terminal - Service Registry', () => {
3939
[ITerminalEnvVarCollectionService, TerminalEnvVarCollectionService],
4040
[IExtensionSingleActivationService, TerminalIndicatorPrompt],
4141
[ITerminalDeactivateService, TerminalDeactivateService],
42-
[IShellIntegrationService, ShellIntegrationService],
42+
[IShellIntegrationDetectionService, ShellIntegrationDetectionService],
4343
].forEach((args) => {
4444
if (args.length === 2) {
4545
services

0 commit comments

Comments
 (0)