2
2
// Licensed under the MIT License.
3
3
4
4
import { inject , injectable , named } from 'inversify' ;
5
- import * as os from 'os' ;
6
5
import { Terminal , Uri } from 'vscode' ;
7
6
import { ICondaService , IInterpreterService , InterpreterType , PythonInterpreter } from '../../interpreter/contracts' ;
8
7
import { sendTelemetryEvent } from '../../telemetry' ;
9
8
import { EventName } from '../../telemetry/constants' ;
10
- import { ITerminalManager } from '../application/types' ;
9
+ import { ITerminalManager , IWorkspaceService } from '../application/types' ;
11
10
import '../extensions' ;
12
11
import { traceDecorators , traceError } from '../logger' ;
13
12
import { IPlatformService } from '../platform/types' ;
14
13
import { IConfigurationService , ICurrentProcess , Resource } from '../types' ;
15
14
import { OSType } from '../utils/platform' ;
15
+ import { ShellDetector } from './shellDetector' ;
16
16
import { ITerminalActivationCommandProvider , ITerminalHelper , TerminalActivationProviders , TerminalShellType } from './types' ;
17
17
18
- // Types of shells can be found here:
19
- // 1. https://wiki.ubuntu.com/ChangingShells
20
- const IS_GITBASH = / ( g i t b a s h .e x e $ ) / i;
21
- const IS_BASH = / ( b a s h .e x e $ | b a s h $ ) / i;
22
- const IS_WSL = / ( w s l .e x e $ ) / i;
23
- const IS_ZSH = / ( z s h $ ) / i;
24
- const IS_KSH = / ( k s h $ ) / i;
25
- const IS_COMMAND = / ( c m d .e x e $ | c m d $ ) / i;
26
- const IS_POWERSHELL = / ( p o w e r s h e l l .e x e $ | p o w e r s h e l l $ ) / i;
27
- const IS_POWERSHELL_CORE = / ( p w s h .e x e $ | p w s h $ ) / i;
28
- const IS_FISH = / ( f i s h $ ) / i;
29
- const IS_CSHELL = / ( c s h $ ) / i;
30
- const IS_TCSHELL = / ( t c s h $ ) / i;
31
- const IS_XONSH = / ( x o n s h $ ) / i;
32
-
33
- const defaultOSShells = {
34
- [ OSType . Linux ] : TerminalShellType . bash ,
35
- [ OSType . OSX ] : TerminalShellType . bash ,
36
- [ OSType . Windows ] : TerminalShellType . commandPrompt ,
37
- [ OSType . Unknown ] : undefined
38
- } ;
39
-
40
18
@injectable ( )
41
19
export class TerminalHelper implements ITerminalHelper {
42
- private readonly detectableShells : Map < TerminalShellType , RegExp > ;
20
+ private readonly shellDetector : ShellDetector ;
43
21
constructor ( @inject ( IPlatformService ) private readonly platform : IPlatformService ,
44
22
@inject ( ITerminalManager ) private readonly terminalManager : ITerminalManager ,
45
23
@inject ( ICondaService ) private readonly condaService : ICondaService ,
@@ -50,61 +28,17 @@ export class TerminalHelper implements ITerminalHelper {
50
28
@inject ( ITerminalActivationCommandProvider ) @named ( TerminalActivationProviders . commandPromptAndPowerShell ) private readonly commandPromptAndPowerShell : ITerminalActivationCommandProvider ,
51
29
@inject ( ITerminalActivationCommandProvider ) @named ( TerminalActivationProviders . pyenv ) private readonly pyenv : ITerminalActivationCommandProvider ,
52
30
@inject ( ITerminalActivationCommandProvider ) @named ( TerminalActivationProviders . pipenv ) private readonly pipenv : ITerminalActivationCommandProvider ,
53
- @inject ( IConfigurationService ) private readonly currentProcess : ICurrentProcess
31
+ @inject ( ICurrentProcess ) private readonly currentProcess : ICurrentProcess ,
32
+ @inject ( IWorkspaceService ) private readonly workspace : IWorkspaceService
54
33
) {
55
- this . detectableShells = new Map < TerminalShellType , RegExp > ( ) ;
56
- this . detectableShells . set ( TerminalShellType . powershell , IS_POWERSHELL ) ;
57
- this . detectableShells . set ( TerminalShellType . gitbash , IS_GITBASH ) ;
58
- this . detectableShells . set ( TerminalShellType . bash , IS_BASH ) ;
59
- this . detectableShells . set ( TerminalShellType . wsl , IS_WSL ) ;
60
- this . detectableShells . set ( TerminalShellType . zsh , IS_ZSH ) ;
61
- this . detectableShells . set ( TerminalShellType . ksh , IS_KSH ) ;
62
- this . detectableShells . set ( TerminalShellType . commandPrompt , IS_COMMAND ) ;
63
- this . detectableShells . set ( TerminalShellType . fish , IS_FISH ) ;
64
- this . detectableShells . set ( TerminalShellType . tcshell , IS_TCSHELL ) ;
65
- this . detectableShells . set ( TerminalShellType . cshell , IS_CSHELL ) ;
66
- this . detectableShells . set ( TerminalShellType . powershellCore , IS_POWERSHELL_CORE ) ;
67
- this . detectableShells . set ( TerminalShellType . xonsh , IS_XONSH ) ;
34
+ this . shellDetector = new ShellDetector ( this . platform , this . currentProcess , this . workspace ) ;
35
+
68
36
}
69
37
public createTerminal ( title ?: string ) : Terminal {
70
38
return this . terminalManager . createTerminal ( { name : title } ) ;
71
39
}
72
40
public identifyTerminalShell ( terminal ?: Terminal ) : TerminalShellType {
73
- let shell = TerminalShellType . other ;
74
- let usingDefaultShell = false ;
75
- const terminalProvided = ! ! terminal ;
76
- // Determine shell based on the name of the terminal.
77
- // See solution here https://github.com/microsoft/vscode/issues/74233#issuecomment-497527337
78
- if ( terminal ) {
79
- shell = this . identifyTerminalShellByName ( terminal . name ) ;
80
- }
81
-
82
- // If still unable to identify, then use fall back to determine path to the default shell.
83
- if ( shell === TerminalShellType . other ) {
84
- const shellPath = getDefaultShell ( this . platform . osType , this . currentProcess ) ;
85
- shell = Array . from ( this . detectableShells . keys ( ) )
86
- . reduce ( ( matchedShell , shellToDetect ) => {
87
- if ( matchedShell === TerminalShellType . other && this . detectableShells . get ( shellToDetect ) ! . test ( shellPath ) ) {
88
- return shellToDetect ;
89
- }
90
- return matchedShell ;
91
- } , TerminalShellType . other ) ;
92
-
93
- // We have restored to using the default shell.
94
- usingDefaultShell = shell !== TerminalShellType . other ;
95
- }
96
- const properties = { failed : shell === TerminalShellType . other , usingDefaultShell, terminalProvided } ;
97
- sendTelemetryEvent ( EventName . TERMINAL_SHELL_IDENTIFICATION , undefined , properties ) ;
98
- return shell ;
99
- }
100
- public identifyTerminalShellByName ( name : string ) : TerminalShellType {
101
- return Array . from ( this . detectableShells . keys ( ) )
102
- . reduce ( ( matchedShell , shellToDetect ) => {
103
- if ( matchedShell === TerminalShellType . other && this . detectableShells . get ( shellToDetect ) ! . test ( name ) ) {
104
- return shellToDetect ;
105
- }
106
- return matchedShell ;
107
- } , TerminalShellType . other ) ;
41
+ return this . shellDetector . identifyTerminalShell ( terminal ) ;
108
42
}
109
43
110
44
public buildCommandForTerminal ( terminalShellType : TerminalShellType , command : string , args : string [ ] ) {
@@ -119,7 +53,10 @@ export class TerminalHelper implements ITerminalHelper {
119
53
return promise ;
120
54
}
121
55
public async getEnvironmentActivationShellCommands ( resource : Resource , interpreter ?: PythonInterpreter ) : Promise < string [ ] | undefined > {
122
- const shell = defaultOSShells [ this . platform . osType ] ;
56
+ if ( this . platform . osType === OSType . Unknown ) {
57
+ return ;
58
+ }
59
+ const shell = this . shellDetector . identifyTerminalShell ( ) ;
123
60
if ( ! shell ) {
124
61
return ;
125
62
}
@@ -181,30 +118,3 @@ export class TerminalHelper implements ITerminalHelper {
181
118
}
182
119
}
183
120
}
184
-
185
- /*
186
- The following code is based on VS Code from https://github.com/microsoft/vscode/blob/5c65d9bfa4c56538150d7f3066318e0db2c6151f/src/vs/workbench/contrib/terminal/node/terminal.ts#L12-L55
187
- This is only a fall back to identify the default shell used by VSC.
188
- On Windows, determine the default shell.
189
- On others, default to bash.
190
- */
191
- function getDefaultShell ( osType : OSType , currentProcess : ICurrentProcess ) : string {
192
- if ( osType === OSType . Windows ) {
193
- return getTerminalDefaultShellWindows ( osType , currentProcess ) ;
194
- }
195
- return '/bin/bash' ;
196
- }
197
- let _TERMINAL_DEFAULT_SHELL_WINDOWS : string | null = null ;
198
- function getTerminalDefaultShellWindows ( osType : OSType , currentProcess : ICurrentProcess ) : string {
199
- if ( ! _TERMINAL_DEFAULT_SHELL_WINDOWS ) {
200
- const isAtLeastWindows10 = osType === OSType . Windows && parseFloat ( os . release ( ) ) >= 10 ;
201
- const is32ProcessOn64Windows = process . env . hasOwnProperty ( 'PROCESSOR_ARCHITEW6432' ) ;
202
- const powerShellPath = `${ process . env . windir } \\${ is32ProcessOn64Windows ? 'Sysnative' : 'System32' } \\WindowsPowerShell\\v1.0\\powershell.exe` ;
203
- _TERMINAL_DEFAULT_SHELL_WINDOWS = isAtLeastWindows10 ? powerShellPath : getWindowsShell ( currentProcess ) ;
204
- }
205
- return _TERMINAL_DEFAULT_SHELL_WINDOWS ;
206
- }
207
-
208
- function getWindowsShell ( currentProcess : ICurrentProcess ) : string {
209
- return currentProcess . env . comspec || 'cmd.exe' ;
210
- }
0 commit comments