Skip to content
Open
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
6 changes: 4 additions & 2 deletions src/features/terminal/runInTerminal.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Terminal, TerminalShellExecution } from 'vscode';
import { PythonEnvironment, PythonTerminalExecutionOptions } from '../../api';
import { traceLog } from '../../common/logging';
import { createDeferred } from '../../common/utils/deferred';
import { onDidEndTerminalShellExecution } from '../../common/window.apis';
import { ShellConstants } from '../common/shellConstants';
import { identifyTerminalShell } from '../common/shellDetector';
import { quoteArgs } from '../execution/execUtils';
import { normalizeShellPath } from './shells/common/shellUtils';
import { traceLog } from '../../common/logging';
import { getClearLineSequence, normalizeShellPath } from './shells/common/shellUtils';

export async function runInTerminal(
environment: PythonEnvironment,
Expand Down Expand Up @@ -52,10 +52,12 @@ export async function runInTerminal(
await deferred.promise;
} else {
let text = quoteArgs([executable, ...allArgs]).join(' ');
const clearLineSequence = getClearLineSequence(terminal);
if (shellType === ShellConstants.PWSH && !text.startsWith('&')) {
// PowerShell requires commands to be prefixed with '&' to run them.
text = `& ${text}`;
}
terminal.sendText(clearLineSequence, false); // Clear the line before sending the command
terminal.sendText(`${text}\n`);
traceLog(`runInTerminal: sendText ${text}`);
}
Expand Down
20 changes: 20 additions & 0 deletions src/features/terminal/shells/common/shellUtils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Terminal } from 'vscode';
import { PythonCommandRunConfiguration, PythonEnvironment } from '../../../../api';
import { isWindows } from '../../../../common/utils/platformUtils';
import { getConfiguration } from '../../../../common/workspace.apis';
import { ShellConstants } from '../../../common/shellConstants';
import { identifyTerminalShell } from '../../../common/shellDetector';
import { quoteArgs } from '../../../execution/execUtils';

/**
Expand Down Expand Up @@ -58,6 +60,7 @@ export function normalizeShellPath(filePath: string, shellType?: string): string
}
return filePath;
}

export function getShellActivationCommand(
shell: string,
environment: PythonEnvironment,
Expand All @@ -76,6 +79,7 @@ export function getShellActivationCommand(

return activation;
}

export function getShellDeactivationCommand(
shell: string,
environment: PythonEnvironment,
Expand Down Expand Up @@ -160,3 +164,19 @@ export const shellIntegrationSupportedShells = [
export function shouldUseProfileActivation(shellType: string): boolean {
return isWsl() || !shellIntegrationSupportedShells.includes(shellType);
}

/**
* Returns the appropriate sequence to clear the current line in the terminal based on the shell type.
* For PowerShell and CMD, it uses the ANSI escape code to clear the entire line and return the cursor to the start.
* For other shells, it uses Ctrl+U to clear from the cursor to the start of the line.
*/
export function getClearLineSequence(terminal: Terminal): string {
const shell = identifyTerminalShell(terminal);
switch (shell) {
case ShellConstants.PWSH:
case ShellConstants.CMD:
return '\x1b[2K\r'; // Clear entire line and return cursor to start
default:
return '\x15'; // Ctrl+U to clear from cursor to start of line
}
}
17 changes: 11 additions & 6 deletions src/features/terminal/terminalActivationState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { PythonEnvironment } from '../../api';
import { traceError, traceInfo, traceVerbose } from '../../common/logging';
import { onDidEndTerminalShellExecution, onDidStartTerminalShellExecution } from '../../common/window.apis';
import { getActivationCommand, getDeactivationCommand } from '../common/activation';
import { getClearLineSequence } from './shells/common/shellUtils';
import { getShellIntegrationTimeout, isTaskTerminal } from './utils';

export interface DidChangeTerminalActivationStateEvent {
Expand Down Expand Up @@ -195,17 +196,21 @@ export class TerminalActivationImpl implements TerminalActivationInternal {
}

private activateLegacy(terminal: Terminal, environment: PythonEnvironment) {
const activationCommands = getActivationCommand(terminal, environment);
if (activationCommands) {
terminal.sendText(activationCommands);
const activationCommand = getActivationCommand(terminal, environment);
const clearLineSequence = getClearLineSequence(terminal);
if (activationCommand) {
terminal.sendText(clearLineSequence, false); // Clear the line before activation command
terminal.sendText(activationCommand);
this.activatedTerminals.set(terminal, environment);
}
}

private deactivateLegacy(terminal: Terminal, environment: PythonEnvironment) {
const deactivationCommands = getDeactivationCommand(terminal, environment);
if (deactivationCommands) {
terminal.sendText(deactivationCommands);
const deactivationCommand = getDeactivationCommand(terminal, environment);
const clearLineSequence = getClearLineSequence(terminal);
if (deactivationCommand) {
terminal.sendText(clearLineSequence, false); // Clear the line before deactivation command
terminal.sendText(deactivationCommand);
this.activatedTerminals.delete(terminal);
}
}
Expand Down
Loading