Skip to content

Commit 2c91ca7

Browse files
Kartik Rajeleanorjboyd
Kartik Raj
authored andcommitted
Open separate Python terminals when running different Python files (microsoft#21202)
Closes microsoft#21097 Closes microsoft#14094
1 parent 0c3034c commit 2c91ca7

File tree

3 files changed

+27
-23
lines changed

3 files changed

+27
-23
lines changed

src/client/common/terminal/factory.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import { inject, injectable } from 'inversify';
55
import { Uri } from 'vscode';
6+
import * as path from 'path';
67
import { IInterpreterService } from '../../interpreter/contracts';
78
import { IServiceContainer } from '../../ioc/types';
89
import { PythonEnvironment } from '../../pythonEnvironments/info';
@@ -26,10 +27,14 @@ export class TerminalServiceFactory implements ITerminalServiceFactory {
2627
public getTerminalService(options: TerminalCreationOptions): ITerminalService {
2728
const resource = options?.resource;
2829
const title = options?.title;
29-
const terminalTitle = typeof title === 'string' && title.trim().length > 0 ? title.trim() : 'Python';
30+
let terminalTitle = typeof title === 'string' && title.trim().length > 0 ? title.trim() : 'Python';
3031
const interpreter = options?.interpreter;
3132
const id = this.getTerminalId(terminalTitle, resource, interpreter);
3233
if (!this.terminalServices.has(id)) {
34+
if (this.terminalServices.size >= 1 && resource) {
35+
terminalTitle = `${terminalTitle}: ${path.basename(resource.fsPath).replace('.py', '')}`;
36+
}
37+
options.title = terminalTitle;
3338
const terminalService = new TerminalService(this.serviceContainer, options);
3439
this.terminalServices.set(id, terminalService);
3540
}
@@ -53,6 +58,6 @@ export class TerminalServiceFactory implements ITerminalServiceFactory {
5358
const workspaceFolder = this.serviceContainer
5459
.get<IWorkspaceService>(IWorkspaceService)
5560
.getWorkspaceFolder(resource || undefined);
56-
return `${title}:${workspaceFolder?.uri.fsPath || ''}:${interpreter?.path}`;
61+
return `${title}:${workspaceFolder?.uri.fsPath || ''}:${interpreter?.path}:${resource?.fsPath || ''}`;
5762
}
5863
}

src/client/terminals/codeExecution/terminalCodeExecution.ts

+18-19
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ import { ICodeExecutionService } from '../../terminals/types';
1919
export class TerminalCodeExecutionProvider implements ICodeExecutionService {
2020
private hasRanOutsideCurrentDrive = false;
2121
protected terminalTitle!: string;
22-
private _terminalService!: ITerminalService;
23-
private replActive?: Promise<boolean>;
22+
private replActive = new Map<string, Promise<boolean>>();
2423
constructor(
2524
@inject(ITerminalServiceFactory) protected readonly terminalServiceFactory: ITerminalServiceFactory,
2625
@inject(IConfigurationService) protected readonly configurationService: IConfigurationService,
@@ -48,19 +47,27 @@ export class TerminalCodeExecutionProvider implements ICodeExecutionService {
4847
await this.getTerminalService(resource).sendText(code);
4948
}
5049
public async initializeRepl(resource?: Uri) {
51-
if (this.replActive && (await this.replActive)) {
52-
await this._terminalService.show();
50+
const terminalService = this.getTerminalService(resource);
51+
let replActive = this.replActive.get(resource?.fsPath || '');
52+
if (replActive && (await replActive)) {
53+
await terminalService.show();
5354
return;
5455
}
55-
this.replActive = new Promise<boolean>(async (resolve) => {
56+
replActive = new Promise<boolean>(async (resolve) => {
5657
const replCommandArgs = await this.getExecutableInfo(resource);
57-
await this.getTerminalService(resource).sendCommand(replCommandArgs.command, replCommandArgs.args);
58+
terminalService.sendCommand(replCommandArgs.command, replCommandArgs.args);
5859

5960
// Give python repl time to start before we start sending text.
6061
setTimeout(() => resolve(true), 1000);
6162
});
63+
this.replActive.set(resource?.fsPath || '', replActive);
64+
this.disposables.push(
65+
terminalService.onDidCloseTerminal(() => {
66+
this.replActive.delete(resource?.fsPath || '');
67+
}),
68+
);
6269

63-
await this.replActive;
70+
await replActive;
6471
}
6572

6673
public async getExecutableInfo(resource?: Uri, args: string[] = []): Promise<PythonExecInfo> {
@@ -77,18 +84,10 @@ export class TerminalCodeExecutionProvider implements ICodeExecutionService {
7784
return this.getExecutableInfo(resource, executeArgs);
7885
}
7986
private getTerminalService(resource?: Uri): ITerminalService {
80-
if (!this._terminalService) {
81-
this._terminalService = this.terminalServiceFactory.getTerminalService({
82-
resource,
83-
title: this.terminalTitle,
84-
});
85-
this.disposables.push(
86-
this._terminalService.onDidCloseTerminal(() => {
87-
this.replActive = undefined;
88-
}),
89-
);
90-
}
91-
return this._terminalService;
87+
return this.terminalServiceFactory.getTerminalService({
88+
resource,
89+
title: this.terminalTitle,
90+
});
9291
}
9392
private async setCwdForFileExecution(file: Uri) {
9493
const pythonSettings = this.configurationService.getSettings(file);

src/test/common/terminals/factory.unit.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ suite('Terminal Service Factory', () => {
105105
expect(notSameAsThirdInstance).to.not.equal(true, 'Instances are the same');
106106
});
107107

108-
test('Ensure same terminal is returned when using resources from the same workspace', () => {
108+
test('Ensure different terminal is returned when using different resources from the same workspace', () => {
109109
const file1A = Uri.file('1a');
110110
const file2A = Uri.file('2a');
111111
const fileB = Uri.file('b');
@@ -131,7 +131,7 @@ suite('Terminal Service Factory', () => {
131131
const terminalForFileB = factory.getTerminalService({ resource: fileB }) as SynchronousTerminalService;
132132

133133
const terminalsAreSameForWorkspaceA = terminalForFile1A.terminalService === terminalForFile2A.terminalService;
134-
expect(terminalsAreSameForWorkspaceA).to.equal(true, 'Instances are not the same for Workspace A');
134+
expect(terminalsAreSameForWorkspaceA).to.equal(false, 'Instances are the same for Workspace A');
135135

136136
const terminalsForWorkspaceABAreDifferent =
137137
terminalForFile1A.terminalService === terminalForFileB.terminalService;

0 commit comments

Comments
 (0)