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 src/features/terminal/shells/bash/bashStartup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ async function isStartupSetup(profile: string, key: string): Promise<ShellSetupS
return ShellSetupState.NotSetup;
}
async function setupStartup(profile: string, key: string, name: string): Promise<boolean> {
if (shellIntegrationForActiveTerminal(name, profile) && !isWsl()) {
if ((await shellIntegrationForActiveTerminal(name, profile)) && !isWsl()) {
removeStartup(profile, key);
return true;
}
Expand Down
20 changes: 13 additions & 7 deletions src/features/terminal/shells/common/shellUtils.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { PythonCommandRunConfiguration, PythonEnvironment } from '../../../../api';
import { traceInfo } from '../../../../common/logging';
import { sleep } from '../../../../common/utils/asyncUtils';
import { isWindows } from '../../../../common/utils/platformUtils';
import { activeTerminalShellIntegration } from '../../../../common/window.apis';
import { ShellConstants } from '../../../common/shellConstants';
import { quoteArgs } from '../../../execution/execUtils';
import { SHELL_INTEGRATION_POLL_INTERVAL, SHELL_INTEGRATION_TIMEOUT } from '../../utils';

function getCommandAsString(command: PythonCommandRunConfiguration[], shell: string, delimiter: string): string {
const parts = [];
Expand Down Expand Up @@ -98,12 +100,19 @@ export function extractProfilePath(content: string): string | undefined {
return undefined;
}

export function shellIntegrationForActiveTerminal(name: string, profile?: string): boolean {
const hasShellIntegration = activeTerminalShellIntegration();
export async function shellIntegrationForActiveTerminal(name: string, profile?: string): Promise<boolean> {
let hasShellIntegration = activeTerminalShellIntegration();
let timeout = 0;

while (!hasShellIntegration && timeout < SHELL_INTEGRATION_TIMEOUT) {
await sleep(SHELL_INTEGRATION_POLL_INTERVAL);
timeout += SHELL_INTEGRATION_POLL_INTERVAL;
hasShellIntegration = activeTerminalShellIntegration();
}

if (hasShellIntegration) {
traceInfo(
`SHELL: Shell integration is available on your active terminal, with name ${name} and profile ${profile}. Python activate scripts will be evaluated at shell integration level, except in WSL.`
`SHELL: Shell integration is available on your active terminal, with name ${name} and profile ${profile}. Python activate scripts will be evaluated at shell integration level, except in WSL.`,
);
return true;
}
Expand All @@ -112,8 +121,5 @@ export function shellIntegrationForActiveTerminal(name: string, profile?: string

export function isWsl(): boolean {
// WSL sets these environment variables
return !!(process.env.WSL_DISTRO_NAME ||
process.env.WSL_INTEROP ||
process.env.WSLENV);
return !!(process.env.WSL_DISTRO_NAME || process.env.WSL_INTEROP || process.env.WSLENV);
}

2 changes: 1 addition & 1 deletion src/features/terminal/shells/fish/fishStartup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ async function isStartupSetup(profilePath: string, key: string): Promise<boolean

async function setupStartup(profilePath: string, key: string): Promise<boolean> {
try {
if (shellIntegrationForActiveTerminal('fish', profilePath) && !isWsl()) {
if ((await shellIntegrationForActiveTerminal('fish', profilePath)) && !isWsl()) {
removeFishStartup(profilePath, key);
return true;
}
Expand Down
2 changes: 1 addition & 1 deletion src/features/terminal/shells/pwsh/pwshStartup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ async function isPowerShellStartupSetup(shell: string, profile: string): Promise
}

async function setupPowerShellStartup(shell: string, profile: string): Promise<boolean> {
if (shellIntegrationForActiveTerminal(shell, profile) && !isWsl()) {
if ((await shellIntegrationForActiveTerminal(shell, profile)) && !isWsl()) {
removePowerShellStartup(shell, profile, POWERSHELL_OLD_ENV_KEY);
removePowerShellStartup(shell, profile, POWERSHELL_ENV_KEY);
return true;
Expand Down
24 changes: 16 additions & 8 deletions src/features/terminal/terminalManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,10 @@ export class TerminalManagerImpl implements TerminalManager {
await this.handleSetupCheck(shells);
}
} else {
traceVerbose(`Auto activation type changed to ${actType}, we are cleaning up shell startup setup`);
// Teardown scripts when switching away from shell startup activation
traceVerbose(
`Auto activation type changed to ${actType}, we are cleaning up shell startup setup`,
);
// Teardown scripts when switching away from shell startup activation
await Promise.all(this.startupScriptProviders.map((p) => p.teardownScripts()));
this.shellSetup.clear();
}
Expand All @@ -145,26 +147,32 @@ export class TerminalManagerImpl implements TerminalManager {
private async handleSetupCheck(shellType: string | Set<string>): Promise<void> {
const shellTypes = typeof shellType === 'string' ? new Set([shellType]) : shellType;
const providers = this.startupScriptProviders.filter((p) => shellTypes.has(p.shellType));
if (providers.length > 0) {
if (providers.length > 0) {
const shellsToSetup: ShellStartupScriptProvider[] = [];
await Promise.all(
providers.map(async (p) => {
const state = await p.isSetup();
const currentSetup = (state === ShellSetupState.Setup);
const currentSetup = state === ShellSetupState.Setup;
// Check if we already processed this shell and the state hasn't changed
if (this.shellSetup.has(p.shellType)) {
const cachedSetup = this.shellSetup.get(p.shellType);
if (currentSetup === cachedSetup) {
traceVerbose(`Shell profile for ${p.shellType} already checked, state unchanged.`);
return;
}
traceVerbose(`Shell profile for ${p.shellType} state changed from ${cachedSetup} to ${currentSetup}, re-evaluating.`);
traceVerbose(
`Shell profile for ${p.shellType} state changed from ${cachedSetup} to ${currentSetup}, re-evaluating.`,
);
}
traceVerbose(`Checking shell profile for ${p.shellType}.`);
if (state === ShellSetupState.NotSetup) {
traceVerbose(`WSL detected: ${isWsl()}, Shell integration available: ${shellIntegrationForActiveTerminal(p.name)}`);
traceVerbose(
`WSL detected: ${isWsl()}, Shell integration available: ${await shellIntegrationForActiveTerminal(
p.name,
)}`,
);

if (shellIntegrationForActiveTerminal(p.name) && !isWsl()) {
if ((await shellIntegrationForActiveTerminal(p.name)) && !isWsl()) {
// Shell integration available and NOT in WSL - skip setup
await p.teardownScripts();
this.shellSetup.set(p.shellType, true);
Expand All @@ -180,7 +188,7 @@ export class TerminalManagerImpl implements TerminalManager {
);
}
} else if (state === ShellSetupState.Setup) {
if (shellIntegrationForActiveTerminal(p.name) && !isWsl()) {
if ((await shellIntegrationForActiveTerminal(p.name)) && !isWsl()) {
await p.teardownScripts();
traceVerbose(
`Shell integration available for ${p.shellType}, removed profile script in favor of shell integration.`,
Expand Down
4 changes: 2 additions & 2 deletions src/features/terminal/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { PythonEnvironment, PythonProject, PythonProjectEnvironmentApi, PythonPr
import { sleep } from '../../common/utils/asyncUtils';
import { getConfiguration, getWorkspaceFolders } from '../../common/workspace.apis';

const SHELL_INTEGRATION_TIMEOUT = 500; // 0.5 seconds
const SHELL_INTEGRATION_POLL_INTERVAL = 20; // 0.02 seconds
export const SHELL_INTEGRATION_TIMEOUT = 500; // 0.5 seconds
export const SHELL_INTEGRATION_POLL_INTERVAL = 20; // 0.02 seconds

export async function waitForShellIntegration(terminal: Terminal): Promise<boolean> {
let timeout = 0;
Expand Down
Loading