Skip to content

Commit 5cd9b65

Browse files
cherry pick in changes for release (#916)
Co-authored-by: Anthony Kim <62267334+anthonykim1@users.noreply.github.com>
1 parent bc94e2f commit 5cd9b65

File tree

8 files changed

+429
-39
lines changed

8 files changed

+429
-39
lines changed

src/features/terminal/shells/bash/bashStartup.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import which from 'which';
55
import { traceError, traceInfo, traceVerbose } from '../../../../common/logging';
66
import { ShellConstants } from '../../../common/shellConstants';
77
import { hasStartupCode, insertStartupCode, removeStartupCode } from '../common/editUtils';
8-
import { shellIntegrationForActiveTerminal } from '../common/shellUtils';
8+
import { isWsl, shellIntegrationForActiveTerminal } from '../common/shellUtils';
99
import { ShellScriptEditState, ShellSetupState, ShellStartupScriptProvider } from '../startupProvider';
1010
import { BASH_ENV_KEY, BASH_OLD_ENV_KEY, BASH_SCRIPT_VERSION, ZSH_ENV_KEY, ZSH_OLD_ENV_KEY } from './bashConstants';
1111

@@ -61,16 +61,14 @@ function getActivationContent(key: string): string {
6161
async function isStartupSetup(profile: string, key: string): Promise<ShellSetupState> {
6262
if (await fs.pathExists(profile)) {
6363
const content = await fs.readFile(profile, 'utf8');
64-
return hasStartupCode(content, regionStart, regionEnd, [key])
65-
? ShellSetupState.Setup
66-
: ShellSetupState.NotSetup;
67-
} else {
68-
return ShellSetupState.NotSetup;
64+
if (hasStartupCode(content, regionStart, regionEnd, [key])) {
65+
return ShellSetupState.Setup;
66+
}
6967
}
68+
return ShellSetupState.NotSetup;
7069
}
71-
7270
async function setupStartup(profile: string, key: string, name: string): Promise<boolean> {
73-
if (shellIntegrationForActiveTerminal(name, profile)) {
71+
if (shellIntegrationForActiveTerminal(name, profile) && !isWsl()) {
7472
removeStartup(profile, key);
7573
return true;
7674
}

src/features/terminal/shells/common/shellUtils.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,17 @@ export function shellIntegrationForActiveTerminal(name: string, profile?: string
103103

104104
if (hasShellIntegration) {
105105
traceInfo(
106-
`SHELL: Shell integration is available on your active terminal. Python activate scripts will be evaluated at shell integration level.
107-
Skipping modification of ${name} profile at: ${profile}`,
106+
`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.`
108107
);
109108
return true;
110109
}
111110
return false;
112111
}
112+
113+
export function isWsl(): boolean {
114+
// WSL sets these environment variables
115+
return !!(process.env.WSL_DISTRO_NAME ||
116+
process.env.WSL_INTEROP ||
117+
process.env.WSLENV);
118+
}
119+

src/features/terminal/shells/fish/fishStartup.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import which from 'which';
66
import { traceError, traceInfo, traceVerbose } from '../../../../common/logging';
77
import { ShellConstants } from '../../../common/shellConstants';
88
import { hasStartupCode, insertStartupCode, removeStartupCode } from '../common/editUtils';
9-
import { shellIntegrationForActiveTerminal } from '../common/shellUtils';
9+
import { isWsl, shellIntegrationForActiveTerminal } from '../common/shellUtils';
1010
import { ShellScriptEditState, ShellSetupState, ShellStartupScriptProvider } from '../startupProvider';
1111
import { FISH_ENV_KEY, FISH_OLD_ENV_KEY, FISH_SCRIPT_VERSION } from './fishConstants';
1212

@@ -58,7 +58,7 @@ async function isStartupSetup(profilePath: string, key: string): Promise<boolean
5858

5959
async function setupStartup(profilePath: string, key: string): Promise<boolean> {
6060
try {
61-
if (shellIntegrationForActiveTerminal('fish', profilePath)) {
61+
if (shellIntegrationForActiveTerminal('fish', profilePath) && !isWsl()) {
6262
removeFishStartup(profilePath, key);
6363
return true;
6464
}

src/features/terminal/shells/pwsh/pwshStartup.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { ShellConstants } from '../../../common/shellConstants';
1313
import { hasStartupCode, insertStartupCode, removeStartupCode } from '../common/editUtils';
1414
import {
1515
extractProfilePath,
16+
isWsl,
1617
PROFILE_TAG_END,
1718
PROFILE_TAG_START,
1819
shellIntegrationForActiveTerminal,
@@ -145,7 +146,7 @@ async function isPowerShellStartupSetup(shell: string, profile: string): Promise
145146
}
146147

147148
async function setupPowerShellStartup(shell: string, profile: string): Promise<boolean> {
148-
if (shellIntegrationForActiveTerminal(shell, profile)) {
149+
if (shellIntegrationForActiveTerminal(shell, profile) && !isWsl()) {
149150
removePowerShellStartup(shell, profile, POWERSHELL_OLD_ENV_KEY);
150151
removePowerShellStartup(shell, profile, POWERSHELL_ENV_KEY);
151152
return true;

src/features/terminal/terminalEnvVarInjector.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,6 @@ export class TerminalEnvVarInjector implements Disposable {
110110
await this.injectEnvironmentVariablesForWorkspace(workspaceFolder);
111111
} else {
112112
// No provided workspace - update all workspaces
113-
this.envVarCollection.clear();
114113

115114
const workspaceFolders = workspace.workspaceFolders;
116115
if (!workspaceFolders || workspaceFolders.length === 0) {
@@ -140,7 +139,6 @@ export class TerminalEnvVarInjector implements Disposable {
140139

141140
// use scoped environment variable collection
142141
const envVarScope = this.getEnvironmentVariableCollectionScoped({ workspaceFolder });
143-
envVarScope.clear(); // Clear existing variables for this workspace
144142

145143
// Check if env file injection is enabled
146144
const config = getConfiguration('python', workspaceUri);

src/features/terminal/terminalManager.ts

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { getConfiguration, onDidChangeConfiguration } from '../../common/workspa
1616
import { isActivatableEnvironment } from '../common/activation';
1717
import { identifyTerminalShell } from '../common/shellDetector';
1818
import { getPythonApi } from '../pythonApi';
19-
import { shellIntegrationForActiveTerminal } from './shells/common/shellUtils';
19+
import { isWsl, shellIntegrationForActiveTerminal } from './shells/common/shellUtils';
2020
import { ShellEnvsProvider, ShellSetupState, ShellStartupScriptProvider } from './shells/startupProvider';
2121
import { handleSettingUpShellProfile } from './shellStartupSetupHandlers';
2222
import {
@@ -129,7 +129,9 @@ export class TerminalManagerImpl implements TerminalManager {
129129
await this.handleSetupCheck(shells);
130130
}
131131
} else {
132-
traceVerbose(`Auto activation type changed to ${actType}`);
132+
traceVerbose(`Auto activation type changed to ${actType}, we are cleaning up shell startup setup`);
133+
// Teardown scripts when switching away from shell startup activation
134+
await Promise.all(this.startupScriptProviders.map((p) => p.teardownScripts()));
133135
this.shellSetup.clear();
134136
}
135137
}
@@ -143,32 +145,47 @@ export class TerminalManagerImpl implements TerminalManager {
143145
private async handleSetupCheck(shellType: string | Set<string>): Promise<void> {
144146
const shellTypes = typeof shellType === 'string' ? new Set([shellType]) : shellType;
145147
const providers = this.startupScriptProviders.filter((p) => shellTypes.has(p.shellType));
146-
if (providers.length > 0) {
148+
if (providers.length > 0) {
147149
const shellsToSetup: ShellStartupScriptProvider[] = [];
148150
await Promise.all(
149151
providers.map(async (p) => {
152+
const state = await p.isSetup();
153+
const currentSetup = (state === ShellSetupState.Setup);
154+
// Check if we already processed this shell and the state hasn't changed
150155
if (this.shellSetup.has(p.shellType)) {
151-
traceVerbose(`Shell profile for ${p.shellType} already checked.`);
152-
return;
156+
const cachedSetup = this.shellSetup.get(p.shellType);
157+
if (currentSetup === cachedSetup) {
158+
traceVerbose(`Shell profile for ${p.shellType} already checked, state unchanged.`);
159+
return;
160+
}
161+
traceVerbose(`Shell profile for ${p.shellType} state changed from ${cachedSetup} to ${currentSetup}, re-evaluating.`);
153162
}
154163
traceVerbose(`Checking shell profile for ${p.shellType}.`);
155-
const state = await p.isSetup();
156164
if (state === ShellSetupState.NotSetup) {
157-
// Check if shell integration is available before marking for setup
158-
if (shellIntegrationForActiveTerminal(p.name)) {
165+
traceVerbose(`WSL detected: ${isWsl()}, Shell integration available: ${shellIntegrationForActiveTerminal(p.name)}`);
166+
167+
if (shellIntegrationForActiveTerminal(p.name) && !isWsl()) {
168+
// Shell integration available and NOT in WSL - skip setup
169+
await p.teardownScripts();
159170
this.shellSetup.set(p.shellType, true);
160171
traceVerbose(
161-
`Shell integration available for ${p.shellType}, skipping prompt, and profile modification.`,
172+
`Shell integration available for ${p.shellType} (not WSL), skipping prompt, and profile modification.`,
162173
);
163174
} else {
164-
// No shell integration, mark for setup
175+
// WSL (regardless of integration) OR no shell integration - needs setup
165176
this.shellSetup.set(p.shellType, false);
166177
shellsToSetup.push(p);
167178
traceVerbose(
168-
`Shell integration is NOT avaoiable. Shell profile for ${p.shellType} is not setup.`,
179+
`Shell integration is NOT available. Shell profile for ${p.shellType} is not setup.`,
169180
);
170181
}
171182
} else if (state === ShellSetupState.Setup) {
183+
if (shellIntegrationForActiveTerminal(p.name) && !isWsl()) {
184+
await p.teardownScripts();
185+
traceVerbose(
186+
`Shell integration available for ${p.shellType}, removed profile script in favor of shell integration.`,
187+
);
188+
}
172189
this.shellSetup.set(p.shellType, true);
173190
traceVerbose(`Shell profile for ${p.shellType} is setup.`);
174191
} else if (state === ShellSetupState.NotInstalled) {
@@ -228,6 +245,7 @@ export class TerminalManagerImpl implements TerminalManager {
228245
let actType = getAutoActivationType();
229246
const shellType = identifyTerminalShell(terminal);
230247
if (actType === ACT_TYPE_SHELL) {
248+
await this.handleSetupCheck(shellType);
231249
actType = await this.getEffectiveActivationType(shellType);
232250
}
233251

src/features/terminal/utils.ts

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -103,32 +103,44 @@ export type AutoActivationType = 'off' | 'command' | 'shellStartup';
103103
* - 'off': Auto-activation is disabled
104104
*
105105
* Priority order:
106-
* 1. python-envs.terminal.autoActivationType setting
107-
* 2. python.terminal.activateEnvironment setting (if false updates python-envs.terminal.autoActivationType)
106+
* 1. python-envs.terminal.autoActivationType
107+
* a. globalRemoteValue
108+
* b. globalLocalValue
109+
* c. globalValue
110+
* 2. python.terminal.activateEnvironment setting (if false, returns 'off' & sets autoActivationType to 'off')
108111
* 3. Default to 'command' if no setting is found
109112
*
110113
* @returns {AutoActivationType} The determined auto-activation type
111114
*/
112115
export function getAutoActivationType(): AutoActivationType {
113116
const pyEnvsConfig = getConfiguration('python-envs');
117+
const pyEnvsActivationType = pyEnvsConfig.inspect<AutoActivationType>('terminal.autoActivationType');
114118

115-
const pyEnvsActivationType = pyEnvsConfig.get<AutoActivationType | undefined>(
116-
'terminal.autoActivationType',
117-
undefined,
118-
);
119-
if (pyEnvsActivationType !== undefined) {
120-
return pyEnvsActivationType;
119+
if (pyEnvsActivationType) {
120+
// Priority order: globalRemoteValue > globalLocalValue > globalValue
121+
const activationType = pyEnvsActivationType as Record<string, unknown>;
122+
123+
if ('globalRemoteValue' in pyEnvsActivationType && activationType.globalRemoteValue !== undefined) {
124+
return activationType.globalRemoteValue as AutoActivationType;
125+
}
126+
if ('globalLocalValue' in pyEnvsActivationType && activationType.globalLocalValue !== undefined) {
127+
return activationType.globalLocalValue as AutoActivationType;
128+
}
129+
if (pyEnvsActivationType.globalValue !== undefined) {
130+
return pyEnvsActivationType.globalValue;
131+
}
121132
}
122133

134+
// If none of the python-envs settings are defined, check the legacy python setting
123135
const pythonConfig = getConfiguration('python');
124136
const pythonActivateSetting = pythonConfig.get<boolean | undefined>('terminal.activateEnvironment', undefined);
125-
if (pythonActivateSetting !== undefined) {
126-
if (pythonActivateSetting === false) {
127-
pyEnvsConfig.set('terminal.autoActivationType', ACT_TYPE_OFF);
128-
}
129-
return pythonActivateSetting ? ACT_TYPE_COMMAND : ACT_TYPE_OFF;
137+
if (pythonActivateSetting === false) {
138+
// Set autoActivationType to 'off' if python.terminal.activateEnvironment is false
139+
pyEnvsConfig.update('terminal.autoActivationType', ACT_TYPE_OFF);
140+
return ACT_TYPE_OFF;
130141
}
131142

143+
// Default to 'command' if no settings are found or if pythonActivateSetting is true/undefined
132144
return ACT_TYPE_COMMAND;
133145
}
134146

0 commit comments

Comments
 (0)