Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 5528e0e

Browse filesBrowse files
flying-sheepKartik Raj
andauthored
Add nushell support to venv activation (#20842)
Fixes #19359 --------- Co-authored-by: Kartik Raj <karraj@microsoft.com>
1 parent 56d1912 commit 5528e0e
Copy full SHA for 5528e0e
Expand file treeCollapse file tree

18 files changed

+287
-115
lines changed

‎.eslintignore

Copy file name to clipboardExpand all lines: .eslintignore
-4Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -207,10 +207,6 @@ src/client/common/terminal/shellDetectors/vscEnvironmentShellDetector.ts
207207
src/client/common/terminal/shellDetectors/terminalNameShellDetector.ts
208208
src/client/common/terminal/shellDetectors/settingsShellDetector.ts
209209
src/client/common/terminal/shellDetectors/baseShellDetector.ts
210-
src/client/common/terminal/environmentActivationProviders/baseActivationProvider.ts
211-
src/client/common/terminal/environmentActivationProviders/commandPrompt.ts
212-
src/client/common/terminal/environmentActivationProviders/bash.ts
213-
src/client/common/terminal/environmentActivationProviders/pyenvActivationProvider.ts
214210
src/client/common/utils/decorators.ts
215211
src/client/common/utils/enum.ts
216212
src/client/common/utils/platform.ts

‎build/existingFiles.json

Copy file name to clipboardExpand all lines: build/existingFiles.json
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@
379379
"src/test/common/socketStream.test.ts",
380380
"src/test/common/terminals/activation.bash.unit.test.ts",
381381
"src/test/common/terminals/activation.commandPrompt.unit.test.ts",
382+
"src/test/common/terminals/activation.nushell.unit.test.ts",
382383
"src/test/common/terminals/activation.conda.unit.test.ts",
383384
"src/test/common/terminals/activation.unit.test.ts",
384385
"src/test/common/terminals/activator/base.unit.test.ts",

‎src/client/common/serviceRegistry.ts

Copy file name to clipboardExpand all lines: src/client/common/serviceRegistry.ts
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ import { IProcessLogger } from './process/types';
6565
import { TerminalActivator } from './terminal/activator';
6666
import { PowershellTerminalActivationFailedHandler } from './terminal/activator/powershellFailedHandler';
6767
import { Bash } from './terminal/environmentActivationProviders/bash';
68+
import { Nushell } from './terminal/environmentActivationProviders/nushell';
6869
import { CommandPromptAndPowerShell } from './terminal/environmentActivationProviders/commandPrompt';
6970
import { CondaActivationCommandProvider } from './terminal/environmentActivationProviders/condaActivationProvider';
7071
import { PipEnvActivationCommandProvider } from './terminal/environmentActivationProviders/pipEnvActivationProvider';
@@ -143,6 +144,11 @@ export function registerTypes(serviceManager: IServiceManager): void {
143144
CommandPromptAndPowerShell,
144145
TerminalActivationProviders.commandPromptAndPowerShell,
145146
);
147+
serviceManager.addSingleton<ITerminalActivationCommandProvider>(
148+
ITerminalActivationCommandProvider,
149+
Nushell,
150+
TerminalActivationProviders.nushell,
151+
);
146152
serviceManager.addSingleton<ITerminalActivationCommandProvider>(
147153
ITerminalActivationCommandProvider,
148154
PyEnvActivationCommandProvider,

‎src/client/common/terminal/environmentActivationProviders/baseActivationProvider.ts

Copy file name to clipboardExpand all lines: src/client/common/terminal/environmentActivationProviders/baseActivationProvider.ts
+4-1Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable max-classes-per-file */
12
// Copyright (c) Microsoft Corporation. All rights reserved.
23
// Licensed under the MIT License.
34

@@ -48,6 +49,7 @@ abstract class BaseActivationCommandProvider implements ITerminalActivationComma
4849
constructor(@inject(IServiceContainer) protected readonly serviceContainer: IServiceContainer) {}
4950

5051
public abstract isShellSupported(targetShell: TerminalShellType): boolean;
52+
5153
public async getActivationCommands(
5254
resource: Uri | undefined,
5355
targetShell: TerminalShellType,
@@ -60,13 +62,14 @@ abstract class BaseActivationCommandProvider implements ITerminalActivationComma
6062
}
6163
return this.getActivationCommandsForInterpreter(interpreter.path, targetShell);
6264
}
65+
6366
public abstract getActivationCommandsForInterpreter(
6467
pythonPath: string,
6568
targetShell: TerminalShellType,
6669
): Promise<string[] | undefined>;
6770
}
6871

69-
export type ActivationScripts = Record<TerminalShellType, string[]>;
72+
export type ActivationScripts = Partial<Record<TerminalShellType, string[]>>;
7073

7174
export abstract class VenvBaseActivationCommandProvider extends BaseActivationCommandProvider {
7275
public isShellSupported(targetShell: TerminalShellType): boolean {

‎src/client/common/terminal/environmentActivationProviders/bash.ts

Copy file name to clipboardExpand all lines: src/client/common/terminal/environmentActivationProviders/bash.ts
+5-6Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { TerminalShellType } from '../types';
77
import { ActivationScripts, VenvBaseActivationCommandProvider } from './baseActivationProvider';
88

99
// For a given shell the scripts are in order of precedence.
10-
const SCRIPTS: ActivationScripts = ({
10+
const SCRIPTS: ActivationScripts = {
1111
// Group 1
1212
[TerminalShellType.wsl]: ['activate.sh', 'activate'],
1313
[TerminalShellType.ksh]: ['activate.sh', 'activate'],
@@ -19,13 +19,12 @@ const SCRIPTS: ActivationScripts = ({
1919
[TerminalShellType.cshell]: ['activate.csh'],
2020
// Group 3
2121
[TerminalShellType.fish]: ['activate.fish'],
22-
} as unknown) as ActivationScripts;
22+
};
2323

2424
export function getAllScripts(): string[] {
2525
const scripts: string[] = [];
26-
for (const key of Object.keys(SCRIPTS)) {
27-
const shell = key as TerminalShellType;
28-
for (const name of SCRIPTS[shell]) {
26+
for (const names of Object.values(SCRIPTS)) {
27+
for (const name of names) {
2928
if (!scripts.includes(name)) {
3029
scripts.push(name);
3130
}
@@ -44,7 +43,7 @@ export class Bash extends VenvBaseActivationCommandProvider {
4443
): Promise<string[] | undefined> {
4544
const scriptFile = await this.findScriptFile(pythonPath, targetShell);
4645
if (!scriptFile) {
47-
return;
46+
return undefined;
4847
}
4948
return [`source ${scriptFile.fileToCommandArgumentForPythonExt()}`];
5049
}

‎src/client/common/terminal/environmentActivationProviders/commandPrompt.ts

Copy file name to clipboardExpand all lines: src/client/common/terminal/environmentActivationProviders/commandPrompt.ts
+15-13Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,18 @@ import { TerminalShellType } from '../types';
99
import { ActivationScripts, VenvBaseActivationCommandProvider } from './baseActivationProvider';
1010

1111
// For a given shell the scripts are in order of precedence.
12-
const SCRIPTS: ActivationScripts = ({
12+
const SCRIPTS: ActivationScripts = {
1313
// Group 1
1414
[TerminalShellType.commandPrompt]: ['activate.bat', 'Activate.ps1'],
1515
// Group 2
1616
[TerminalShellType.powershell]: ['Activate.ps1', 'activate.bat'],
1717
[TerminalShellType.powershellCore]: ['Activate.ps1', 'activate.bat'],
18-
} as unknown) as ActivationScripts;
18+
};
1919

2020
export function getAllScripts(pathJoin: (...p: string[]) => string): string[] {
2121
const scripts: string[] = [];
22-
for (const key of Object.keys(SCRIPTS)) {
23-
const shell = key as TerminalShellType;
24-
for (const name of SCRIPTS[shell]) {
22+
for (const names of Object.values(SCRIPTS)) {
23+
for (const name of names) {
2524
if (!scripts.includes(name)) {
2625
scripts.push(
2726
name,
@@ -38,13 +37,14 @@ export function getAllScripts(pathJoin: (...p: string[]) => string): string[] {
3837
@injectable()
3938
export class CommandPromptAndPowerShell extends VenvBaseActivationCommandProvider {
4039
protected readonly scripts: ActivationScripts;
40+
4141
constructor(@inject(IServiceContainer) serviceContainer: IServiceContainer) {
4242
super(serviceContainer);
43-
this.scripts = ({} as unknown) as ActivationScripts;
44-
for (const key of Object.keys(SCRIPTS)) {
43+
this.scripts = {};
44+
for (const [key, names] of Object.entries(SCRIPTS)) {
4545
const shell = key as TerminalShellType;
4646
const scripts: string[] = [];
47-
for (const name of SCRIPTS[shell]) {
47+
for (const name of names) {
4848
scripts.push(
4949
name,
5050
// We also add scripts in subdirs.
@@ -62,21 +62,23 @@ export class CommandPromptAndPowerShell extends VenvBaseActivationCommandProvide
6262
): Promise<string[] | undefined> {
6363
const scriptFile = await this.findScriptFile(pythonPath, targetShell);
6464
if (!scriptFile) {
65-
return;
65+
return undefined;
6666
}
6767

6868
if (targetShell === TerminalShellType.commandPrompt && scriptFile.endsWith('activate.bat')) {
6969
return [scriptFile.fileToCommandArgumentForPythonExt()];
70-
} else if (
70+
}
71+
if (
7172
(targetShell === TerminalShellType.powershell || targetShell === TerminalShellType.powershellCore) &&
7273
scriptFile.endsWith('Activate.ps1')
7374
) {
7475
return [`& ${scriptFile.fileToCommandArgumentForPythonExt()}`];
75-
} else if (targetShell === TerminalShellType.commandPrompt && scriptFile.endsWith('Activate.ps1')) {
76+
}
77+
if (targetShell === TerminalShellType.commandPrompt && scriptFile.endsWith('Activate.ps1')) {
7678
// lets not try to run the powershell file from command prompt (user may not have powershell)
7779
return [];
78-
} else {
79-
return;
8080
}
81+
82+
return undefined;
8183
}
8284
}
+40Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
import { injectable } from 'inversify';
5+
import '../../extensions';
6+
import { TerminalShellType } from '../types';
7+
import { ActivationScripts, VenvBaseActivationCommandProvider } from './baseActivationProvider';
8+
9+
// For a given shell the scripts are in order of precedence.
10+
const SCRIPTS: ActivationScripts = {
11+
[TerminalShellType.nushell]: ['activate.nu'],
12+
};
13+
14+
export function getAllScripts(): string[] {
15+
const scripts: string[] = [];
16+
for (const names of Object.values(SCRIPTS)) {
17+
for (const name of names) {
18+
if (!scripts.includes(name)) {
19+
scripts.push(name);
20+
}
21+
}
22+
}
23+
return scripts;
24+
}
25+
26+
@injectable()
27+
export class Nushell extends VenvBaseActivationCommandProvider {
28+
protected readonly scripts = SCRIPTS;
29+
30+
public async getActivationCommandsForInterpreter(
31+
pythonPath: string,
32+
targetShell: TerminalShellType,
33+
): Promise<string[] | undefined> {
34+
const scriptFile = await this.findScriptFile(pythonPath, targetShell);
35+
if (!scriptFile) {
36+
return undefined;
37+
}
38+
return [`overlay use ${scriptFile.fileToCommandArgumentForPythonExt()}`];
39+
}
40+
}

‎src/client/common/terminal/environmentActivationProviders/pyenvActivationProvider.ts

Copy file name to clipboardExpand all lines: src/client/common/terminal/environmentActivationProviders/pyenvActivationProvider.ts
+3-2Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { ITerminalActivationCommandProvider, TerminalShellType } from '../types'
1414
export class PyEnvActivationCommandProvider implements ITerminalActivationCommandProvider {
1515
constructor(@inject(IServiceContainer) private readonly serviceContainer: IServiceContainer) {}
1616

17+
// eslint-disable-next-line class-methods-use-this
1718
public isShellSupported(_targetShell: TerminalShellType): boolean {
1819
return true;
1920
}
@@ -23,7 +24,7 @@ export class PyEnvActivationCommandProvider implements ITerminalActivationComman
2324
.get<IInterpreterService>(IInterpreterService)
2425
.getActiveInterpreter(resource);
2526
if (!interpreter || interpreter.envType !== EnvironmentType.Pyenv || !interpreter.envName) {
26-
return;
27+
return undefined;
2728
}
2829

2930
return [`pyenv shell ${interpreter.envName.toCommandArgumentForPythonExt()}`];
@@ -37,7 +38,7 @@ export class PyEnvActivationCommandProvider implements ITerminalActivationComman
3738
.get<IInterpreterService>(IInterpreterService)
3839
.getInterpreterDetails(pythonPath);
3940
if (!interpreter || interpreter.envType !== EnvironmentType.Pyenv || !interpreter.envName) {
40-
return;
41+
return undefined;
4142
}
4243

4344
return [`pyenv shell ${interpreter.envName.toCommandArgumentForPythonExt()}`];

‎src/client/common/terminal/helper.ts

Copy file name to clipboardExpand all lines: src/client/common/terminal/helper.ts
+5-2Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ export class TerminalHelper implements ITerminalHelper {
4242
@named(TerminalActivationProviders.commandPromptAndPowerShell)
4343
private readonly commandPromptAndPowerShell: ITerminalActivationCommandProvider,
4444
@inject(ITerminalActivationCommandProvider)
45+
@named(TerminalActivationProviders.nushell)
46+
private readonly nushell: ITerminalActivationCommandProvider,
47+
@inject(ITerminalActivationCommandProvider)
4548
@named(TerminalActivationProviders.pyenv)
4649
private readonly pyenv: ITerminalActivationCommandProvider,
4750
@inject(ITerminalActivationCommandProvider)
@@ -72,7 +75,7 @@ export class TerminalHelper implements ITerminalHelper {
7275
resource?: Uri,
7376
interpreter?: PythonEnvironment,
7477
): Promise<string[] | undefined> {
75-
const providers = [this.pipenv, this.pyenv, this.bashCShellFish, this.commandPromptAndPowerShell];
78+
const providers = [this.pipenv, this.pyenv, this.bashCShellFish, this.commandPromptAndPowerShell, this.nushell];
7679
const promise = this.getActivationCommands(resource || undefined, interpreter, terminalShellType, providers);
7780
this.sendTelemetry(
7881
terminalShellType,
@@ -90,7 +93,7 @@ export class TerminalHelper implements ITerminalHelper {
9093
if (this.platform.osType === OSType.Unknown) {
9194
return;
9295
}
93-
const providers = [this.bashCShellFish, this.commandPromptAndPowerShell];
96+
const providers = [this.bashCShellFish, this.commandPromptAndPowerShell, this.nushell];
9497
const promise = this.getActivationCommands(resource, interpreter, shell, providers);
9598
this.sendTelemetry(
9699
shell,

‎src/client/common/terminal/shellDetectors/baseShellDetector.ts

Copy file name to clipboardExpand all lines: src/client/common/terminal/shellDetectors/baseShellDetector.ts
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const IS_POWERSHELL_CORE = /(pwsh$)/i;
3030
const IS_FISH = /(fish$)/i;
3131
const IS_CSHELL = /(csh$)/i;
3232
const IS_TCSHELL = /(tcsh$)/i;
33+
const IS_NUSHELL = /(nu$)/i;
3334
const IS_XONSH = /(xonsh$)/i;
3435

3536
const detectableShells = new Map<TerminalShellType, RegExp>();
@@ -43,6 +44,7 @@ detectableShells.set(TerminalShellType.commandPrompt, IS_COMMAND);
4344
detectableShells.set(TerminalShellType.fish, IS_FISH);
4445
detectableShells.set(TerminalShellType.tcshell, IS_TCSHELL);
4546
detectableShells.set(TerminalShellType.cshell, IS_CSHELL);
47+
detectableShells.set(TerminalShellType.nushell, IS_NUSHELL);
4648
detectableShells.set(TerminalShellType.powershellCore, IS_POWERSHELL_CORE);
4749
detectableShells.set(TerminalShellType.xonsh, IS_XONSH);
4850

‎src/client/common/terminal/types.ts

Copy file name to clipboardExpand all lines: src/client/common/terminal/types.ts
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { IDisposable, Resource } from '../types';
1111
export enum TerminalActivationProviders {
1212
bashCShellFish = 'bashCShellFish',
1313
commandPromptAndPowerShell = 'commandPromptAndPowerShell',
14+
nushell = 'nushell',
1415
pyenv = 'pyenv',
1516
conda = 'conda',
1617
pipenv = 'pipenv',
@@ -26,6 +27,7 @@ export enum TerminalShellType {
2627
fish = 'fish',
2728
cshell = 'cshell',
2829
tcshell = 'tshell',
30+
nushell = 'nushell',
2931
wsl = 'wsl',
3032
xonsh = 'xonsh',
3133
other = 'other',

‎src/test/common/installer.test.ts

Copy file name to clipboardExpand all lines: src/test/common/installer.test.ts
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import { TerminalActivator } from '../../client/common/terminal/activator';
5151
import { PowershellTerminalActivationFailedHandler } from '../../client/common/terminal/activator/powershellFailedHandler';
5252
import { Bash } from '../../client/common/terminal/environmentActivationProviders/bash';
5353
import { CommandPromptAndPowerShell } from '../../client/common/terminal/environmentActivationProviders/commandPrompt';
54+
import { Nushell } from '../../client/common/terminal/environmentActivationProviders/nushell';
5455
import { CondaActivationCommandProvider } from '../../client/common/terminal/environmentActivationProviders/condaActivationProvider';
5556
import { PipEnvActivationCommandProvider } from '../../client/common/terminal/environmentActivationProviders/pipEnvActivationProvider';
5657
import { PyEnvActivationCommandProvider } from '../../client/common/terminal/environmentActivationProviders/pyenvActivationProvider';
@@ -214,6 +215,11 @@ suite('Installer', () => {
214215
CommandPromptAndPowerShell,
215216
TerminalActivationProviders.commandPromptAndPowerShell,
216217
);
218+
ioc.serviceManager.addSingleton<ITerminalActivationCommandProvider>(
219+
ITerminalActivationCommandProvider,
220+
Nushell,
221+
TerminalActivationProviders.nushell,
222+
);
217223
ioc.serviceManager.addSingleton<ITerminalActivationCommandProvider>(
218224
ITerminalActivationCommandProvider,
219225
PyEnvActivationCommandProvider,

‎src/test/common/moduleInstaller.test.ts

Copy file name to clipboardExpand all lines: src/test/common/moduleInstaller.test.ts
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import { TerminalActivator } from '../../client/common/terminal/activator';
5050
import { PowershellTerminalActivationFailedHandler } from '../../client/common/terminal/activator/powershellFailedHandler';
5151
import { Bash } from '../../client/common/terminal/environmentActivationProviders/bash';
5252
import { CommandPromptAndPowerShell } from '../../client/common/terminal/environmentActivationProviders/commandPrompt';
53+
import { Nushell } from '../../client/common/terminal/environmentActivationProviders/nushell';
5354
import { CondaActivationCommandProvider } from '../../client/common/terminal/environmentActivationProviders/condaActivationProvider';
5455
import { PipEnvActivationCommandProvider } from '../../client/common/terminal/environmentActivationProviders/pipEnvActivationProvider';
5556
import { PyEnvActivationCommandProvider } from '../../client/common/terminal/environmentActivationProviders/pyenvActivationProvider';
@@ -225,6 +226,11 @@ suite('Module Installer', () => {
225226
CommandPromptAndPowerShell,
226227
TerminalActivationProviders.commandPromptAndPowerShell,
227228
);
229+
ioc.serviceManager.addSingleton<ITerminalActivationCommandProvider>(
230+
ITerminalActivationCommandProvider,
231+
Nushell,
232+
TerminalActivationProviders.nushell,
233+
);
228234
ioc.serviceManager.addSingleton<ITerminalActivationCommandProvider>(
229235
ITerminalActivationCommandProvider,
230236
PyEnvActivationCommandProvider,

‎src/test/common/serviceRegistry.unit.test.ts

Copy file name to clipboardExpand all lines: src/test/common/serviceRegistry.unit.test.ts
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import { TerminalActivator } from '../../client/common/terminal/activator';
4040
import { PowershellTerminalActivationFailedHandler } from '../../client/common/terminal/activator/powershellFailedHandler';
4141
import { Bash } from '../../client/common/terminal/environmentActivationProviders/bash';
4242
import { CommandPromptAndPowerShell } from '../../client/common/terminal/environmentActivationProviders/commandPrompt';
43+
import { Nushell } from '../../client/common/terminal/environmentActivationProviders/nushell';
4344
import { CondaActivationCommandProvider } from '../../client/common/terminal/environmentActivationProviders/condaActivationProvider';
4445
import { PipEnvActivationCommandProvider } from '../../client/common/terminal/environmentActivationProviders/pipEnvActivationProvider';
4546
import { PyEnvActivationCommandProvider } from '../../client/common/terminal/environmentActivationProviders/pyenvActivationProvider';
@@ -113,6 +114,7 @@ suite('Common - Service Registry', () => {
113114
CommandPromptAndPowerShell,
114115
TerminalActivationProviders.commandPromptAndPowerShell,
115116
],
117+
[ITerminalActivationCommandProvider, Nushell, TerminalActivationProviders.nushell],
116118
[IToolExecutionPath, PipEnvExecutionPath, ToolExecutionPath.pipenv],
117119
[ITerminalActivationCommandProvider, CondaActivationCommandProvider, TerminalActivationProviders.conda],
118120
[ITerminalActivationCommandProvider, PipEnvActivationCommandProvider, TerminalActivationProviders.pipenv],

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.