Skip to content

Commit 85aa6ae

Browse files
committed
Make activation great
1 parent fcb9848 commit 85aa6ae

File tree

5 files changed

+105
-26
lines changed

5 files changed

+105
-26
lines changed

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

Lines changed: 3 additions & 2 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 { isWsl, shellIntegrationForActiveTerminal } from '../common/shellUtils';
8+
import { getShellIntegrationEnabledCache, 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

@@ -69,7 +69,8 @@ async function isStartupSetup(profile: string, key: string): Promise<ShellSetupS
6969
return ShellSetupState.NotSetup;
7070
}
7171
async function setupStartup(profile: string, key: string, name: string): Promise<boolean> {
72-
if ((await shellIntegrationForActiveTerminal(name, profile)) && !isWsl()) {
72+
const shellIntegrationEnabled = await getShellIntegrationEnabledCache();
73+
if ((shellIntegrationEnabled || (await shellIntegrationForActiveTerminal(name, profile))) && !isWsl()) {
7374
removeStartup(profile, key);
7475
return true;
7576
}

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

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import { PythonCommandRunConfiguration, PythonEnvironment } from '../../../../api';
22
import { traceInfo } from '../../../../common/logging';
3+
import { getGlobalPersistentState } from '../../../../common/persistentState';
34
import { sleep } from '../../../../common/utils/asyncUtils';
45
import { isWindows } from '../../../../common/utils/platformUtils';
56
import { activeTerminalShellIntegration } from '../../../../common/window.apis';
7+
import { getConfiguration } from '../../../../common/workspace.apis';
68
import { ShellConstants } from '../../../common/shellConstants';
79
import { quoteArgs } from '../../../execution/execUtils';
810
import { SHELL_INTEGRATION_POLL_INTERVAL, SHELL_INTEGRATION_TIMEOUT } from '../../utils';
911

12+
export const SHELL_INTEGRATION_STATE_KEY = 'shellIntegration.enabled';
13+
1014
function getCommandAsString(command: PythonCommandRunConfiguration[], shell: string, delimiter: string): string {
1115
const parts = [];
1216
for (const cmd of command) {
@@ -114,6 +118,11 @@ export async function shellIntegrationForActiveTerminal(name: string, profile?:
114118
traceInfo(
115119
`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.`,
116120
);
121+
122+
// Update persistent storage to reflect that shell integration is available
123+
const persistentState = await getGlobalPersistentState();
124+
await persistentState.set(SHELL_INTEGRATION_STATE_KEY, true);
125+
117126
return true;
118127
}
119128
return false;
@@ -123,3 +132,27 @@ export function isWsl(): boolean {
123132
// WSL sets these environment variables
124133
return !!(process.env.WSL_DISTRO_NAME || process.env.WSL_INTEROP || process.env.WSLENV);
125134
}
135+
136+
export async function getShellIntegrationEnabledCache(): Promise<boolean> {
137+
const persistentState = await getGlobalPersistentState();
138+
// Check VS Code setting for shell integration using inspect (all scopes)
139+
const shellIntegrationInspect =
140+
getConfiguration('terminal.integrated').inspect<boolean>('shellIntegration.enabled');
141+
142+
let shellIntegrationEnabled = true;
143+
if (shellIntegrationInspect) {
144+
// Priority: workspaceFolder > workspace > global > default
145+
if (shellIntegrationInspect.workspaceFolderValue !== undefined) {
146+
shellIntegrationEnabled = shellIntegrationInspect.workspaceFolderValue;
147+
} else if (shellIntegrationInspect.workspaceValue !== undefined) {
148+
shellIntegrationEnabled = shellIntegrationInspect.workspaceValue;
149+
} else if (shellIntegrationInspect.globalValue !== undefined) {
150+
shellIntegrationEnabled = shellIntegrationInspect.globalValue;
151+
} else if (shellIntegrationInspect.defaultValue !== undefined) {
152+
shellIntegrationEnabled = shellIntegrationInspect.defaultValue;
153+
}
154+
}
155+
156+
await persistentState.set(SHELL_INTEGRATION_STATE_KEY, shellIntegrationEnabled);
157+
return shellIntegrationEnabled;
158+
}

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

Lines changed: 3 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 { isWsl, shellIntegrationForActiveTerminal } from '../common/shellUtils';
9+
import { getShellIntegrationEnabledCache, 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,8 @@ async function isStartupSetup(profilePath: string, key: string): Promise<boolean
5858

5959
async function setupStartup(profilePath: string, key: string): Promise<boolean> {
6060
try {
61-
if ((await shellIntegrationForActiveTerminal('fish', profilePath)) && !isWsl()) {
61+
const shellIntegrationEnabled = await getShellIntegrationEnabledCache();
62+
if ((shellIntegrationEnabled || (await shellIntegrationForActiveTerminal('fish', profilePath))) && !isWsl()) {
6263
removeFishStartup(profilePath, key);
6364
return true;
6465
}

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

Lines changed: 4 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+
getShellIntegrationEnabledCache,
1617
isWsl,
1718
PROFILE_TAG_END,
1819
PROFILE_TAG_START,
@@ -168,7 +169,9 @@ async function isPowerShellStartupSetup(shell: string, profile: string): Promise
168169
}
169170

170171
async function setupPowerShellStartup(shell: string, profile: string): Promise<boolean> {
171-
if ((await shellIntegrationForActiveTerminal(shell, profile)) && !isWsl()) {
172+
const shellIntegrationEnabled = await getShellIntegrationEnabledCache();
173+
174+
if ((shellIntegrationEnabled || (await shellIntegrationForActiveTerminal(shell, profile))) && !isWsl()) {
172175
removePowerShellStartup(shell, profile, POWERSHELL_OLD_ENV_KEY);
173176
removePowerShellStartup(shell, profile, POWERSHELL_ENV_KEY);
174177
return true;

src/features/terminal/terminalManager.ts

Lines changed: 62 additions & 21 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 { isWsl, shellIntegrationForActiveTerminal } from './shells/common/shellUtils';
19+
import { getShellIntegrationEnabledCache, isWsl, shellIntegrationForActiveTerminal } from './shells/common/shellUtils';
2020
import { ShellEnvsProvider, ShellSetupState, ShellStartupScriptProvider } from './shells/startupProvider';
2121
import { handleSettingUpShellProfile } from './shellStartupSetupHandlers';
2222
import {
@@ -137,6 +137,20 @@ export class TerminalManagerImpl implements TerminalManager {
137137
this.shellSetup.clear();
138138
}
139139
}
140+
if (e.affectsConfiguration('terminal.integrated.shellIntegration.enabled')) {
141+
traceInfo('Shell integration setting changed, invalidating cache');
142+
const updatedShellIntegrationSetting = await getShellIntegrationEnabledCache();
143+
if (!updatedShellIntegrationSetting) {
144+
const shells = new Set(
145+
terminals()
146+
.map((t) => identifyTerminalShell(t))
147+
.filter((t) => t !== 'unknown'),
148+
);
149+
if (shells.size > 0) {
150+
await this.handleSetupCheck(shells);
151+
}
152+
}
153+
}
140154
}),
141155
onDidChangeWindowState((e) => {
142156
this.hasFocus = e.focused;
@@ -152,27 +166,19 @@ export class TerminalManagerImpl implements TerminalManager {
152166
await Promise.all(
153167
providers.map(async (p) => {
154168
const state = await p.isSetup();
155-
const currentSetup = state === ShellSetupState.Setup;
156-
// Check if we already processed this shell and the state hasn't changed
157-
if (this.shellSetup.has(p.shellType)) {
158-
const cachedSetup = this.shellSetup.get(p.shellType);
159-
if (currentSetup === cachedSetup) {
160-
traceVerbose(`Shell profile for ${p.shellType} already checked, state unchanged.`);
161-
return;
162-
}
163-
traceVerbose(
164-
`Shell profile for ${p.shellType} state changed from ${cachedSetup} to ${currentSetup}, re-evaluating.`,
165-
);
166-
}
167-
traceVerbose(`Checking shell profile for ${p.shellType}.`);
169+
const shellIntegrationEnabled = await getShellIntegrationEnabledCache();
170+
traceVerbose(`Checking shell profile for ${p.shellType}, with state: ${state}`);
168171
if (state === ShellSetupState.NotSetup) {
169172
traceVerbose(
170-
`WSL detected: ${isWsl()}, Shell integration available: ${await shellIntegrationForActiveTerminal(
173+
`WSL detected: ${isWsl()}, Shell integration available from setting, or active terminal: ${shellIntegrationEnabled}, or ${await shellIntegrationForActiveTerminal(
171174
p.name,
172175
)}`,
173176
);
174177

175-
if ((await shellIntegrationForActiveTerminal(p.name)) && !isWsl()) {
178+
if (
179+
(shellIntegrationEnabled || (await shellIntegrationForActiveTerminal(p.name))) &&
180+
!isWsl()
181+
) {
176182
// Shell integration available and NOT in WSL - skip setup
177183
await p.teardownScripts();
178184
this.shellSetup.set(p.shellType, true);
@@ -188,7 +194,10 @@ export class TerminalManagerImpl implements TerminalManager {
188194
);
189195
}
190196
} else if (state === ShellSetupState.Setup) {
191-
if ((await shellIntegrationForActiveTerminal(p.name)) && !isWsl()) {
197+
if (
198+
(shellIntegrationEnabled || (await shellIntegrationForActiveTerminal(p.name))) &&
199+
!isWsl()
200+
) {
192201
await p.teardownScripts();
193202
traceVerbose(
194203
`Shell integration available for ${p.shellType}, removed profile script in favor of shell integration.`,
@@ -213,10 +222,42 @@ export class TerminalManagerImpl implements TerminalManager {
213222
return;
214223
}
215224

216-
setImmediate(async () => {
217-
// Avoid blocking this setup on user interaction.
218-
await handleSettingUpShellProfile(shellsToSetup, (p, v) => this.shellSetup.set(p.shellType, v));
219-
});
225+
if (!(await getShellIntegrationEnabledCache())) {
226+
// Shell integration is disabled - prompt for ALL shells
227+
setImmediate(async () => {
228+
// Avoid blocking this setup on user interaction.
229+
await handleSettingUpShellProfile(shellsToSetup, (p, v) => this.shellSetup.set(p.shellType, v));
230+
});
231+
traceVerbose('Shell integration is not available, prompting for shell modifications');
232+
} else {
233+
// // Shell integration is enabled - only prompt for CMD shells
234+
// // (CMD doesn't support shell integration well, so we still need profile modification)
235+
// const cmdShellsToSetup = shellsToSetup.filter((p) => p.shellType === ShellConstants.CMD);
236+
// const nonCmdShells = shellsToSetup.filter((p) => p.shellType !== ShellConstants.CMD);
237+
238+
// // Mark non-CMD shells as setup complete since they'll use shell integration
239+
// nonCmdShells.forEach((p) => {
240+
// this.shellSetup.set(p.shellType, true);
241+
// traceVerbose(
242+
// `Shell integration is enabled for ${p.shellType}, marking as setup complete (will use shell integration instead of profile modification).`,
243+
// );
244+
// });
245+
246+
// if (cmdShellsToSetup.length > 0) {
247+
// setImmediate(async () => {
248+
// await handleSettingUpShellProfile(cmdShellsToSetup, (p, v) =>
249+
// this.shellSetup.set(p.shellType, v),
250+
// );
251+
// });
252+
// } else {
253+
// traceVerbose('Shell integration is enabled and no CMD shells need setup.');
254+
// }
255+
setImmediate(async () => {
256+
// Avoid blocking this setup on user interaction.
257+
await handleSettingUpShellProfile(shellsToSetup, (p, v) => this.shellSetup.set(p.shellType, v));
258+
});
259+
traceVerbose('Shell integration is available, prompt for shell modification if needed');
260+
}
220261
}
221262
}
222263

0 commit comments

Comments
 (0)