Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
"python.tensorBoard.logDirectory.description": "Set this setting to your preferred TensorBoard log directory to skip log directory prompt when starting TensorBoard.",
"python.tensorBoard.logDirectory.markdownDeprecationMessage": "Tensorboard support has been moved to the extension [Tensorboard extension](https://marketplace.visualstudio.com/items?itemName=ms-toolsai.tensorboard). Instead use the setting `tensorBoard.logDirectory`.",
"python.tensorBoard.logDirectory.deprecationMessage": "Tensorboard support has been moved to the extension Tensorboard extension. Instead use the setting `tensorBoard.logDirectory`.",
"python.terminal.shellIntegration.enabled.description": "Enable [shell integration](https://code.visualstudio.com/docs/terminal/shell-integration) for the terminals running python. Shell integration enhances the terminal experience by enabling command decorations, run recent command, improving accessibility among other things.",
"python.terminal.shellIntegration.enabled.description": "Enable [shell integration](https://code.visualstudio.com/docs/terminal/shell-integration) for the terminals running python. Shell integration enhances the terminal experience by enabling command decorations, run recent command, improving accessibility among other things. Note: PyREPL (available in Python 3.13+) is automatically disabled when shell integration is enabled to avoid cursor indentation issues.",
"python.terminal.activateEnvInCurrentTerminal.description": "Activate Python Environment in the current Terminal on load of the Extension.",
"python.terminal.activateEnvironment.description": "Activate Python Environment in all Terminals created.",
"python.terminal.executeInFileDir.description": "When executing a file in the terminal, whether to use execute in the file's directory, instead of the current open folder.",
Expand Down
3 changes: 1 addition & 2 deletions python_files/pythonrc.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import readline

original_ps1 = ">>> "
use_shell_integration = sys.version_info < (3, 13)
is_wsl = "microsoft-standard-WSL" in platform.release()


Expand Down Expand Up @@ -75,7 +74,7 @@ def __str__(self):
return result


if sys.platform != "win32" and (not is_wsl) and use_shell_integration:
if sys.platform != "win32" and (not is_wsl):
sys.ps1 = PS1()

if sys.platform == "darwin":
Expand Down
4 changes: 3 additions & 1 deletion src/client/common/configSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,9 @@ export class PythonSettings implements IPythonSettings {
launchArgs: [],
activateEnvironment: true,
activateEnvInCurrentTerminal: false,
enableShellIntegration: false,
shellIntegration: {
enabled: false,
},
};

this.REPL = pythonSettings.get<IREPLSettings>('REPL')!;
Expand Down
4 changes: 3 additions & 1 deletion src/client/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,9 @@ export interface ITerminalSettings {
readonly launchArgs: string[];
readonly activateEnvironment: boolean;
readonly activateEnvInCurrentTerminal: boolean;
readonly enableShellIntegration: boolean;
readonly shellIntegration: {
enabled: boolean;
};
}

export interface IREPLSettings {
Expand Down
3 changes: 1 addition & 2 deletions src/client/extensionActivation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ import { DebuggerTypeName } from './debugger/constants';
import { StopWatch } from './common/utils/stopWatch';
import { registerReplCommands, registerReplExecuteOnEnter, registerStartNativeReplCommand } from './repl/replCommands';
import { registerTriggerForTerminalREPL } from './terminals/codeExecution/terminalReplWatcher';
import { registerBasicRepl, registerPythonStartup } from './terminals/pythonStartup';
import { registerPythonStartup } from './terminals/pythonStartup';
import { registerPixiFeatures } from './pythonEnvironments/common/environmentManagers/pixi';
import { registerCustomTerminalLinkProvider } from './terminals/pythonStartupLinkProvider';
import { registerEnvExtFeatures } from './envExt/api.internal';
Expand Down Expand Up @@ -184,7 +184,6 @@ async function activateLegacy(ext: ExtensionState, startupStopWatch: StopWatch):
serviceManager.get<ITerminalAutoActivation>(ITerminalAutoActivation).register();

await registerPythonStartup(ext.context);
await registerBasicRepl(ext.context);

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

Expand Down
12 changes: 12 additions & 0 deletions src/client/terminals/codeExecution/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,12 @@ export class CodeExecutionHelper implements ICodeExecutionHelper {
const endLineVal = activeEditor?.selection?.end.line ?? 0;
const emptyHighlightVal = activeEditor?.selection?.isEmpty ?? true;
let smartSendSettingsEnabledVal = true;
let shellIntegrationEnabled = false;
const configuration = this.serviceContainer.get<IConfigurationService>(IConfigurationService);
if (configuration) {
const pythonSettings = configuration.getSettings(this.activeResourceService.getActiveResource());
smartSendSettingsEnabledVal = pythonSettings.REPL.enableREPLSmartSend;
shellIntegrationEnabled = pythonSettings.terminal.shellIntegration.enabled;
}

const input = JSON.stringify({
Expand All @@ -125,6 +127,16 @@ export class CodeExecutionHelper implements ICodeExecutionHelper {
await this.moveToNextBlock(lineOffset, activeEditor);
}

// For new _pyrepl for Python3.13+ && !shellIntegration, we need to send code via bracketed paste mode.
if (object.attach_bracket_paste && !shellIntegrationEnabled && _replType === ReplType.terminal) {
let trimmedNormalized = object.normalized.replace(/\n$/, '');
if (trimmedNormalized.endsWith(':\n')) {
// In case where statement is unfinished via :, truncate so auto-indentation lands nicely.
trimmedNormalized = trimmedNormalized.replace(/\n$/, '');
}
return `\u001b[200~${trimmedNormalized}\u001b[201~`;
}

return parse(object.normalized);
} catch (ex) {
traceError(ex, 'Python: Failed to normalize code for execution in terminal');
Expand Down
8 changes: 3 additions & 5 deletions src/client/terminals/pythonStartup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ async function applyPythonStartupSetting(context: ExtensionContext): Promise<voi
const sourcePath = path.join(EXTENSION_ROOT_DIR, 'python_files', 'pythonrc.py');
await copy(Uri.file(sourcePath), destPath, { overwrite: true });
context.environmentVariableCollection.replace('PYTHONSTARTUP', destPath.fsPath);
// When shell integration is enabled, we disable PyREPL from cpython.
context.environmentVariableCollection.replace('PYTHON_BASIC_REPL', '1');
} else {
context.environmentVariableCollection.delete('PYTHONSTARTUP');
context.environmentVariableCollection.delete('PYTHON_BASIC_REPL');
}
}

Expand All @@ -36,8 +39,3 @@ export async function registerPythonStartup(context: ExtensionContext): Promise<
}),
);
}

export async function registerBasicRepl(context: ExtensionContext): Promise<void> {
// TODO: Configurable by setting
context.environmentVariableCollection.replace('PYTHON_BASIC_REPL', '1');
}
7 changes: 4 additions & 3 deletions src/test/terminals/shellIntegration/pythonStartup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
} from 'vscode';
import { assert } from 'chai';
import * as workspaceApis from '../../../client/common/vscodeApis/workspaceApis';
import { registerBasicRepl, registerPythonStartup } from '../../../client/terminals/pythonStartup';
import { registerPythonStartup } from '../../../client/terminals/pythonStartup';
import { IExtensionContext } from '../../../client/common/types';
import * as pythonStartupLinkProvider from '../../../client/terminals/pythonStartupLinkProvider';
import { CustomTerminalLinkProvider } from '../../../client/terminals/pythonStartupLinkProvider';
Expand Down Expand Up @@ -135,8 +135,9 @@ suite('Terminal - Shell Integration with PYTHONSTARTUP', () => {
globalEnvironmentVariableCollection.verify((c) => c.delete('PYTHONSTARTUP'), TypeMoq.Times.once());
});

test('PYTHON_BASIC_REPL is set when registerBasicRepl is called', async () => {
await registerBasicRepl(context.object);
test('PYTHON_BASIC_REPL is set when shell integration is enabled', async () => {
pythonConfig.setup((p) => p.get('terminal.shellIntegration.enabled')).returns(() => true);
await registerPythonStartup(context.object);
globalEnvironmentVariableCollection.verify(
(c) => c.replace('PYTHON_BASIC_REPL', '1', TypeMoq.It.isAny()),
TypeMoq.Times.once(),
Expand Down