Skip to content

Commit fdca3c1

Browse files
committed
use sendText when sending to >= 3.13
1 parent 1187591 commit fdca3c1

File tree

2 files changed

+56
-4
lines changed

2 files changed

+56
-4
lines changed

src/client/common/terminal/service.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,16 +110,18 @@ export class TerminalService implements ITerminalService, Disposable {
110110
const config = getConfiguration('python');
111111
const pythonrcSetting = config.get<boolean>('terminal.shellIntegration.enabled');
112112

113+
let minorVersion: number | undefined;
113114
// Need to check for if Python version is >= 3.13 since we have turned off SI on python side.
114115
// Because we are not sending explicit commandline info to core, it will inject ^C. (We want to avoid)
115116
if (this.options && this.options.resource) {
116117
const pythonVersion = await getActiveInterpreter(
117118
this.options.resource,
118119
this.serviceContainer.get<IInterpreterService>(IInterpreterService),
119120
);
120-
const minorVersion = pythonVersion?.version?.minor;
121+
minorVersion = pythonVersion?.version?.minor;
122+
}
121123

122-
if ((isPythonShell && !pythonrcSetting) || (isPythonShell && isWindows()) || ((minorVersion ?? 0) >= 13)) {
124+
if ((isPythonShell && !pythonrcSetting) || (isPythonShell && isWindows()) || (minorVersion ?? 0) >= 13) {
123125
// If user has explicitly disabled SI for Python, use sendText for inside Terminal REPL.
124126
terminal.sendText(commandLine);
125127
return undefined;

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

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,29 @@ import {
1111
TerminalShellExecution,
1212
TerminalShellExecutionEndEvent,
1313
TerminalShellIntegration,
14+
Uri,
1415
Terminal as VSCodeTerminal,
1516
WorkspaceConfiguration,
1617
} from 'vscode';
1718
import { ITerminalManager, IWorkspaceService } from '../../../client/common/application/types';
1819
import { EXTENSION_ROOT_DIR } from '../../../client/common/constants';
1920
import { IPlatformService } from '../../../client/common/platform/types';
2021
import { TerminalService } from '../../../client/common/terminal/service';
21-
import { ITerminalActivator, ITerminalHelper, TerminalShellType } from '../../../client/common/terminal/types';
22+
import {
23+
ITerminalActivator,
24+
ITerminalHelper,
25+
TerminalCreationOptions,
26+
TerminalShellType,
27+
} from '../../../client/common/terminal/types';
2228
import { IDisposableRegistry } from '../../../client/common/types';
2329
import { IServiceContainer } from '../../../client/ioc/types';
2430
import { ITerminalAutoActivation } from '../../../client/terminals/types';
2531
import { createPythonInterpreter } from '../../utils/interpreters';
2632
import * as workspaceApis from '../../../client/common/vscodeApis/workspaceApis';
2733
import * as platform from '../../../client/common/utils/platform';
2834
import * as extapi from '../../../client/envExt/api.internal';
35+
import { IInterpreterService } from '../../../client/interpreter/contracts';
36+
import { PythonEnvironment } from '../../../client/pythonEnvironments/info';
2937

3038
suite('Terminal Service', () => {
3139
let service: TerminalService;
@@ -46,6 +54,8 @@ suite('Terminal Service', () => {
4654
let editorConfig: TypeMoq.IMock<WorkspaceConfiguration>;
4755
let isWindowsStub: sinon.SinonStub;
4856
let useEnvExtensionStub: sinon.SinonStub;
57+
let interpreterService: TypeMoq.IMock<IInterpreterService>;
58+
let options: TypeMoq.IMock<TerminalCreationOptions>;
4959

5060
setup(() => {
5161
useEnvExtensionStub = sinon.stub(extapi, 'useEnvExtension');
@@ -92,6 +102,13 @@ suite('Terminal Service', () => {
92102
disposables = [];
93103

94104
mockServiceContainer = TypeMoq.Mock.ofType<IServiceContainer>();
105+
interpreterService = TypeMoq.Mock.ofType<IInterpreterService>();
106+
interpreterService
107+
.setup((i) => i.getActiveInterpreter(TypeMoq.It.isAny()))
108+
.returns(() => Promise.resolve(({ path: 'ps' } as unknown) as PythonEnvironment));
109+
110+
options = TypeMoq.Mock.ofType<TerminalCreationOptions>();
111+
options.setup((o) => o.resource).returns(() => Uri.parse('a'));
95112

96113
mockServiceContainer.setup((c) => c.get(ITerminalManager)).returns(() => terminalManager.object);
97114
mockServiceContainer.setup((c) => c.get(ITerminalHelper)).returns(() => terminalHelper.object);
@@ -100,6 +117,7 @@ suite('Terminal Service', () => {
100117
mockServiceContainer.setup((c) => c.get(IWorkspaceService)).returns(() => workspaceService.object);
101118
mockServiceContainer.setup((c) => c.get(ITerminalActivator)).returns(() => terminalActivator.object);
102119
mockServiceContainer.setup((c) => c.get(ITerminalAutoActivation)).returns(() => terminalAutoActivator.object);
120+
mockServiceContainer.setup((c) => c.get(IInterpreterService)).returns(() => interpreterService.object);
103121
getConfigurationStub = sinon.stub(workspaceApis, 'getConfiguration');
104122
isWindowsStub = sinon.stub(platform, 'isWindows');
105123
pythonConfig = TypeMoq.Mock.ofType<WorkspaceConfiguration>();
@@ -117,6 +135,8 @@ suite('Terminal Service', () => {
117135
}
118136
disposables.filter((item) => !!item).forEach((item) => item.dispose());
119137
sinon.restore();
138+
// reset setup for interpreterService
139+
interpreterService.reset();
120140
});
121141

122142
test('Ensure terminal is disposed', async () => {
@@ -239,7 +259,7 @@ suite('Terminal Service', () => {
239259
terminal.verify((t) => t.sendText(TypeMoq.It.isValue(textToSend)), TypeMoq.Times.exactly(1));
240260
});
241261

242-
test('Ensure sendText is NOT called when Python shell integration and terminal shell integration are both enabled - Mac, Linux', async () => {
262+
test('Ensure sendText is NOT called when Python shell integration and terminal shell integration are both enabled - Mac, Linux && Python < 3.13', async () => {
243263
isWindowsStub.returns(false);
244264
pythonConfig
245265
.setup((p) => p.get('terminal.shellIntegration.enabled'))
@@ -261,6 +281,36 @@ suite('Terminal Service', () => {
261281
terminal.verify((t) => t.sendText(TypeMoq.It.isValue(textToSend)), TypeMoq.Times.never());
262282
});
263283

284+
test('Ensure sendText is called when Python shell integration and terminal shell integration are both enabled - Mac, Linux && Python >= 3.13', async () => {
285+
interpreterService.reset();
286+
287+
interpreterService
288+
.setup((i) => i.getActiveInterpreter(TypeMoq.It.isAny()))
289+
.returns(() =>
290+
Promise.resolve({ path: 'yo', version: { major: 3, minor: 13, patch: 0 } } as PythonEnvironment),
291+
);
292+
293+
isWindowsStub.returns(false);
294+
pythonConfig
295+
.setup((p) => p.get('terminal.shellIntegration.enabled'))
296+
.returns(() => true)
297+
.verifiable(TypeMoq.Times.once());
298+
299+
terminalHelper
300+
.setup((helper) => helper.getEnvironmentActivationCommands(TypeMoq.It.isAny(), TypeMoq.It.isAny()))
301+
.returns(() => Promise.resolve(undefined));
302+
303+
service = new TerminalService(mockServiceContainer.object, options.object);
304+
const textToSend = 'Some Text';
305+
terminalHelper.setup((h) => h.identifyTerminalShell(TypeMoq.It.isAny())).returns(() => TerminalShellType.bash);
306+
terminalManager.setup((t) => t.createTerminal(TypeMoq.It.isAny())).returns(() => terminal.object);
307+
308+
await service.ensureTerminal();
309+
await service.executeCommand(textToSend, true);
310+
311+
terminal.verify((t) => t.sendText(TypeMoq.It.isValue(textToSend)), TypeMoq.Times.once());
312+
});
313+
264314
test('Ensure sendText IS called even when Python shell integration and terminal shell integration are both enabled - Window', async () => {
265315
isWindowsStub.returns(true);
266316
pythonConfig

0 commit comments

Comments
 (0)