Skip to content

Commit cb859ca

Browse files
authored
Revert: Run in dedicated terminal feature due to regressions (#21418)
For #21393
1 parent 06f7db2 commit cb859ca

File tree

11 files changed

+55
-159
lines changed

11 files changed

+55
-159
lines changed

package.json

-19
Original file line numberDiff line numberDiff line change
@@ -392,12 +392,6 @@
392392
"icon": "$(play)",
393393
"title": "%python.command.python.execInTerminalIcon.title%"
394394
},
395-
{
396-
"category": "Python",
397-
"command": "python.execInDedicatedTerminal",
398-
"icon": "$(play)",
399-
"title": "%python.command.python.execInDedicatedTerminal.title%"
400-
},
401395
{
402396
"category": "Python",
403397
"command": "python.debugInTerminal",
@@ -1728,13 +1722,6 @@
17281722
"title": "%python.command.python.execInTerminalIcon.title%",
17291723
"when": "false"
17301724
},
1731-
{
1732-
"category": "Python",
1733-
"command": "python.execInDedicatedTerminal",
1734-
"icon": "$(play)",
1735-
"title": "%python.command.python.execInDedicatedTerminal.title%",
1736-
"when": "false"
1737-
},
17381725
{
17391726
"category": "Python",
17401727
"command": "python.debugInTerminal",
@@ -1893,12 +1880,6 @@
18931880
"title": "%python.command.python.execInTerminalIcon.title%",
18941881
"when": "resourceLangId == python && !isInDiffEditor && !virtualWorkspace && shellExecutionSupported"
18951882
},
1896-
{
1897-
"command": "python.execInDedicatedTerminal",
1898-
"group": "navigation@0",
1899-
"title": "%python.command.python.execInDedicatedTerminal.title%",
1900-
"when": "resourceLangId == python && !isInDiffEditor && !virtualWorkspace && shellExecutionSupported"
1901-
},
19021883
{
19031884
"command": "python.debugInTerminal",
19041885
"group": "navigation@1",

package.nls.json

-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
"python.command.python.execInTerminal.title": "Run Python File in Terminal",
88
"python.command.python.debugInTerminal.title": "Debug Python File",
99
"python.command.python.execInTerminalIcon.title": "Run Python File",
10-
"python.command.python.execInDedicatedTerminal.title": "Run Python File in Dedicated Terminal",
1110
"python.command.python.setInterpreter.title": "Select Interpreter",
1211
"python.command.python.clearWorkspaceInterpreter.title": "Clear Workspace Interpreter Setting",
1312
"python.command.python.viewOutput.title": "Show Output",

src/client/common/constants.ts

-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ export namespace Commands {
4444
export const Enable_SourceMap_Support = 'python.enableSourceMapSupport';
4545
export const Exec_In_Terminal = 'python.execInTerminal';
4646
export const Exec_In_Terminal_Icon = 'python.execInTerminal-icon';
47-
export const Exec_In_Separate_Terminal = 'python.execInDedicatedTerminal';
4847
export const Exec_Selection_In_Django_Shell = 'python.execSelectionInDjangoShell';
4948
export const Exec_Selection_In_Terminal = 'python.execSelectionInTerminal';
5049
export const GetSelectedInterpreterPath = 'python.interpreterPath';

src/client/common/terminal/factory.ts

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

44
import { inject, injectable } from 'inversify';
55
import { Uri } from 'vscode';
6-
import * as path from 'path';
76
import { IInterpreterService } from '../../interpreter/contracts';
87
import { IServiceContainer } from '../../ioc/types';
98
import { PythonEnvironment } from '../../pythonEnvironments/info';
@@ -24,17 +23,13 @@ export class TerminalServiceFactory implements ITerminalServiceFactory {
2423
) {
2524
this.terminalServices = new Map<string, TerminalService>();
2625
}
27-
public getTerminalService(options: TerminalCreationOptions & { newTerminalPerFile?: boolean }): ITerminalService {
26+
public getTerminalService(options: TerminalCreationOptions): ITerminalService {
2827
const resource = options?.resource;
2928
const title = options?.title;
30-
let terminalTitle = typeof title === 'string' && title.trim().length > 0 ? title.trim() : 'Python';
29+
const terminalTitle = typeof title === 'string' && title.trim().length > 0 ? title.trim() : 'Python';
3130
const interpreter = options?.interpreter;
32-
const id = this.getTerminalId(terminalTitle, resource, interpreter, options.newTerminalPerFile);
31+
const id = this.getTerminalId(terminalTitle, resource, interpreter);
3332
if (!this.terminalServices.has(id)) {
34-
if (resource && options.newTerminalPerFile) {
35-
terminalTitle = `${terminalTitle}: ${path.basename(resource.fsPath).replace('.py', '')}`;
36-
}
37-
options.title = terminalTitle;
3833
const terminalService = new TerminalService(this.serviceContainer, options);
3934
this.terminalServices.set(id, terminalService);
4035
}
@@ -51,19 +46,13 @@ export class TerminalServiceFactory implements ITerminalServiceFactory {
5146
title = typeof title === 'string' && title.trim().length > 0 ? title.trim() : 'Python';
5247
return new TerminalService(this.serviceContainer, { resource, title });
5348
}
54-
private getTerminalId(
55-
title: string,
56-
resource?: Uri,
57-
interpreter?: PythonEnvironment,
58-
newTerminalPerFile?: boolean,
59-
): string {
49+
private getTerminalId(title: string, resource?: Uri, interpreter?: PythonEnvironment): string {
6050
if (!resource && !interpreter) {
6151
return title;
6252
}
6353
const workspaceFolder = this.serviceContainer
6454
.get<IWorkspaceService>(IWorkspaceService)
6555
.getWorkspaceFolder(resource || undefined);
66-
const fileId = resource && newTerminalPerFile ? resource.fsPath : '';
67-
return `${title}:${workspaceFolder?.uri.fsPath || ''}:${interpreter?.path}:${fileId}`;
56+
return `${title}:${workspaceFolder?.uri.fsPath || ''}:${interpreter?.path}`;
6857
}
6958
}

src/client/common/terminal/types.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ export interface ITerminalServiceFactory {
9797
* @returns {ITerminalService}
9898
* @memberof ITerminalServiceFactory
9999
*/
100-
getTerminalService(options: TerminalCreationOptions & { newTerminalPerFile?: boolean }): ITerminalService;
100+
getTerminalService(options: TerminalCreationOptions): ITerminalService;
101101
createTerminalService(resource?: Uri, title?: string): ITerminalService;
102102
}
103103

src/client/telemetry/index.ts

-6
Original file line numberDiff line numberDiff line change
@@ -827,12 +827,6 @@ export interface IEventNamePropertyMapping {
827827
* @type {('command' | 'icon')}
828828
*/
829829
trigger?: 'command' | 'icon';
830-
/**
831-
* Whether user chose to execute this Python file in a separate terminal or not.
832-
*
833-
* @type {boolean}
834-
*/
835-
newTerminalPerFile?: boolean;
836830
};
837831
/**
838832
* Telemetry Event sent when user executes code against Django Shell.

src/client/terminals/codeExecution/codeExecutionManager.ts

+21-35
Original file line numberDiff line numberDiff line change
@@ -36,31 +36,25 @@ export class CodeExecutionManager implements ICodeExecutionManager {
3636
}
3737

3838
public registerCommands() {
39-
[Commands.Exec_In_Terminal, Commands.Exec_In_Terminal_Icon, Commands.Exec_In_Separate_Terminal].forEach(
40-
(cmd) => {
41-
this.disposableRegistry.push(
42-
this.commandManager.registerCommand(cmd as any, async (file: Resource) => {
43-
const interpreterService = this.serviceContainer.get<IInterpreterService>(IInterpreterService);
44-
const interpreter = await interpreterService.getActiveInterpreter(file);
45-
if (!interpreter) {
46-
this.commandManager
47-
.executeCommand(Commands.TriggerEnvironmentSelection, file)
48-
.then(noop, noop);
49-
return;
50-
}
51-
const trigger = cmd === Commands.Exec_In_Terminal ? 'command' : 'icon';
52-
await this.executeFileInTerminal(file, trigger, {
53-
newTerminalPerFile: cmd === Commands.Exec_In_Separate_Terminal,
39+
[Commands.Exec_In_Terminal, Commands.Exec_In_Terminal_Icon].forEach((cmd) => {
40+
this.disposableRegistry.push(
41+
this.commandManager.registerCommand(cmd as any, async (file: Resource) => {
42+
const interpreterService = this.serviceContainer.get<IInterpreterService>(IInterpreterService);
43+
const interpreter = await interpreterService.getActiveInterpreter(file);
44+
if (!interpreter) {
45+
this.commandManager.executeCommand(Commands.TriggerEnvironmentSelection, file).then(noop, noop);
46+
return;
47+
}
48+
const trigger = cmd === Commands.Exec_In_Terminal ? 'command' : 'icon';
49+
await this.executeFileInTerminal(file, trigger)
50+
.then(() => {
51+
if (this.shouldTerminalFocusOnStart(file))
52+
this.commandManager.executeCommand('workbench.action.terminal.focus');
5453
})
55-
.then(() => {
56-
if (this.shouldTerminalFocusOnStart(file))
57-
this.commandManager.executeCommand('workbench.action.terminal.focus');
58-
})
59-
.catch((ex) => traceError('Failed to execute file in terminal', ex));
60-
}),
61-
);
62-
},
63-
);
54+
.catch((ex) => traceError('Failed to execute file in terminal', ex));
55+
}),
56+
);
57+
});
6458
this.disposableRegistry.push(
6559
this.commandManager.registerCommand(Commands.Exec_Selection_In_Terminal as any, async (file: Resource) => {
6660
const interpreterService = this.serviceContainer.get<IInterpreterService>(IInterpreterService);
@@ -93,16 +87,8 @@ export class CodeExecutionManager implements ICodeExecutionManager {
9387
),
9488
);
9589
}
96-
private async executeFileInTerminal(
97-
file: Resource,
98-
trigger: 'command' | 'icon',
99-
options?: { newTerminalPerFile: boolean },
100-
): Promise<void> {
101-
sendTelemetryEvent(EventName.EXECUTION_CODE, undefined, {
102-
scope: 'file',
103-
trigger,
104-
newTerminalPerFile: options?.newTerminalPerFile,
105-
});
90+
private async executeFileInTerminal(file: Resource, trigger: 'command' | 'icon') {
91+
sendTelemetryEvent(EventName.EXECUTION_CODE, undefined, { scope: 'file', trigger });
10692
const codeExecutionHelper = this.serviceContainer.get<ICodeExecutionHelper>(ICodeExecutionHelper);
10793
file = file instanceof Uri ? file : undefined;
10894
let fileToExecute = file ? file : await codeExecutionHelper.getFileToExecute();
@@ -124,7 +110,7 @@ export class CodeExecutionManager implements ICodeExecutionManager {
124110
}
125111

126112
const executionService = this.serviceContainer.get<ICodeExecutionService>(ICodeExecutionService, 'standard');
127-
await executionService.executeFile(fileToExecute, options);
113+
await executionService.executeFile(fileToExecute);
128114
}
129115

130116
@captureTelemetry(EventName.EXECUTION_CODE, { scope: 'selection' }, false)

src/client/terminals/codeExecution/terminalCodeExecution.ts

+18-16
Original file line numberDiff line numberDiff line change
@@ -19,6 +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;
2223
private replActive?: Promise<boolean>;
2324
constructor(
2425
@inject(ITerminalServiceFactory) protected readonly terminalServiceFactory: ITerminalServiceFactory,
@@ -29,13 +30,13 @@ export class TerminalCodeExecutionProvider implements ICodeExecutionService {
2930
@inject(IInterpreterService) protected readonly interpreterService: IInterpreterService,
3031
) {}
3132

32-
public async executeFile(file: Uri, options?: { newTerminalPerFile: boolean }) {
33+
public async executeFile(file: Uri) {
3334
await this.setCwdForFileExecution(file);
3435
const { command, args } = await this.getExecuteFileArgs(file, [
3536
file.fsPath.fileToCommandArgumentForPythonExt(),
3637
]);
3738

38-
await this.getTerminalService(file, options).sendCommand(command, args);
39+
await this.getTerminalService(file).sendCommand(command, args);
3940
}
4041

4142
public async execute(code: string, resource?: Uri): Promise<void> {
@@ -47,23 +48,17 @@ export class TerminalCodeExecutionProvider implements ICodeExecutionService {
4748
await this.getTerminalService(resource).sendText(code);
4849
}
4950
public async initializeRepl(resource?: Uri) {
50-
const terminalService = this.getTerminalService(resource);
5151
if (this.replActive && (await this.replActive)) {
52-
await terminalService.show();
52+
await this._terminalService.show();
5353
return;
5454
}
5555
this.replActive = new Promise<boolean>(async (resolve) => {
5656
const replCommandArgs = await this.getExecutableInfo(resource);
57-
terminalService.sendCommand(replCommandArgs.command, replCommandArgs.args);
57+
await this.getTerminalService(resource).sendCommand(replCommandArgs.command, replCommandArgs.args);
5858

5959
// Give python repl time to start before we start sending text.
6060
setTimeout(() => resolve(true), 1000);
6161
});
62-
this.disposables.push(
63-
terminalService.onDidCloseTerminal(() => {
64-
this.replActive = undefined;
65-
}),
66-
);
6762

6863
await this.replActive;
6964
}
@@ -81,12 +76,19 @@ export class TerminalCodeExecutionProvider implements ICodeExecutionService {
8176
public async getExecuteFileArgs(resource?: Uri, executeArgs: string[] = []): Promise<PythonExecInfo> {
8277
return this.getExecutableInfo(resource, executeArgs);
8378
}
84-
private getTerminalService(resource?: Uri, options?: { newTerminalPerFile: boolean }): ITerminalService {
85-
return this.terminalServiceFactory.getTerminalService({
86-
resource,
87-
title: this.terminalTitle,
88-
newTerminalPerFile: options?.newTerminalPerFile,
89-
});
79+
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;
9092
}
9193
private async setCwdForFileExecution(file: Uri) {
9294
const pythonSettings = this.configurationService.getSettings(file);

src/client/terminals/types.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export const ICodeExecutionService = Symbol('ICodeExecutionService');
88

99
export interface ICodeExecutionService {
1010
execute(code: string, resource?: Uri): Promise<void>;
11-
executeFile(file: Uri, options?: { newTerminalPerFile: boolean }): Promise<void>;
11+
executeFile(file: Uri): Promise<void>;
1212
initializeRepl(resource?: Uri): Promise<void>;
1313
}
1414

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

+1-46
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 different resources from the same workspace', () => {
108+
test('Ensure same terminal is returned when using resources from the same workspace', () => {
109109
const file1A = Uri.file('1a');
110110
const file2A = Uri.file('2a');
111111
const fileB = Uri.file('b');
@@ -140,49 +140,4 @@ suite('Terminal Service Factory', () => {
140140
'Instances should be different for different workspaces',
141141
);
142142
});
143-
144-
test('When `newTerminalPerFile` is true, ensure different terminal is returned when using different resources from the same workspace', () => {
145-
const file1A = Uri.file('1a');
146-
const file2A = Uri.file('2a');
147-
const fileB = Uri.file('b');
148-
const workspaceUriA = Uri.file('A');
149-
const workspaceUriB = Uri.file('B');
150-
const workspaceFolderA = TypeMoq.Mock.ofType<WorkspaceFolder>();
151-
workspaceFolderA.setup((w) => w.uri).returns(() => workspaceUriA);
152-
const workspaceFolderB = TypeMoq.Mock.ofType<WorkspaceFolder>();
153-
workspaceFolderB.setup((w) => w.uri).returns(() => workspaceUriB);
154-
155-
workspaceService
156-
.setup((w) => w.getWorkspaceFolder(TypeMoq.It.isValue(file1A)))
157-
.returns(() => workspaceFolderA.object);
158-
workspaceService
159-
.setup((w) => w.getWorkspaceFolder(TypeMoq.It.isValue(file2A)))
160-
.returns(() => workspaceFolderA.object);
161-
workspaceService
162-
.setup((w) => w.getWorkspaceFolder(TypeMoq.It.isValue(fileB)))
163-
.returns(() => workspaceFolderB.object);
164-
165-
const terminalForFile1A = factory.getTerminalService({
166-
resource: file1A,
167-
newTerminalPerFile: true,
168-
}) as SynchronousTerminalService;
169-
const terminalForFile2A = factory.getTerminalService({
170-
resource: file2A,
171-
newTerminalPerFile: true,
172-
}) as SynchronousTerminalService;
173-
const terminalForFileB = factory.getTerminalService({
174-
resource: fileB,
175-
newTerminalPerFile: true,
176-
}) as SynchronousTerminalService;
177-
178-
const terminalsAreSameForWorkspaceA = terminalForFile1A.terminalService === terminalForFile2A.terminalService;
179-
expect(terminalsAreSameForWorkspaceA).to.equal(false, 'Instances are the same for Workspace A');
180-
181-
const terminalsForWorkspaceABAreDifferent =
182-
terminalForFile1A.terminalService === terminalForFileB.terminalService;
183-
expect(terminalsForWorkspaceABAreDifferent).to.equal(
184-
false,
185-
'Instances should be different for different workspaces',
186-
);
187-
});
188143
});

src/test/terminals/codeExecution/codeExecutionManager.unit.test.ts

+8-17
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,12 @@ suite('Terminal - Code Execution Manager', () => {
7777
executionManager.registerCommands();
7878

7979
const sorted = registered.sort();
80-
expect(sorted).to.deep.equal(
81-
[
82-
Commands.Exec_In_Separate_Terminal,
83-
Commands.Exec_In_Terminal,
84-
Commands.Exec_In_Terminal_Icon,
85-
Commands.Exec_Selection_In_Django_Shell,
86-
Commands.Exec_Selection_In_Terminal,
87-
].sort(),
88-
);
80+
expect(sorted).to.deep.equal([
81+
Commands.Exec_In_Terminal,
82+
Commands.Exec_In_Terminal_Icon,
83+
Commands.Exec_Selection_In_Django_Shell,
84+
Commands.Exec_Selection_In_Terminal,
85+
]);
8986
});
9087

9188
test('Ensure executeFileInterTerminal will do nothing if no file is avialble', async () => {
@@ -138,10 +135,7 @@ suite('Terminal - Code Execution Manager', () => {
138135
const fileToExecute = Uri.file('x');
139136
await commandHandler!(fileToExecute);
140137
helper.verify(async (h) => h.getFileToExecute(), TypeMoq.Times.never());
141-
executionService.verify(
142-
async (e) => e.executeFile(TypeMoq.It.isValue(fileToExecute), TypeMoq.It.isAny()),
143-
TypeMoq.Times.once(),
144-
);
138+
executionService.verify(async (e) => e.executeFile(TypeMoq.It.isValue(fileToExecute)), TypeMoq.Times.once());
145139
});
146140

147141
test('Ensure executeFileInterTerminal will use active file', async () => {
@@ -170,10 +164,7 @@ suite('Terminal - Code Execution Manager', () => {
170164
.returns(() => executionService.object);
171165

172166
await commandHandler!(fileToExecute);
173-
executionService.verify(
174-
async (e) => e.executeFile(TypeMoq.It.isValue(fileToExecute), TypeMoq.It.isAny()),
175-
TypeMoq.Times.once(),
176-
);
167+
executionService.verify(async (e) => e.executeFile(TypeMoq.It.isValue(fileToExecute)), TypeMoq.Times.once());
177168
});
178169

179170
async function testExecutionOfSelectionWithoutAnyActiveDocument(commandId: string, executionSericeId: string) {

0 commit comments

Comments
 (0)