22// Licensed under the MIT License. 
33
44import  {  inject ,  injectable ,  named  }  from  'inversify' ; 
5- import  *  as  os  from  'os' ; 
65import  {  Terminal ,  Uri  }  from  'vscode' ; 
76import  {  ICondaService ,  IInterpreterService ,  InterpreterType ,  PythonInterpreter  }  from  '../../interpreter/contracts' ; 
87import  {  sendTelemetryEvent  }  from  '../../telemetry' ; 
98import  {  EventName  }  from  '../../telemetry/constants' ; 
10- import  {  ITerminalManager  }  from  '../application/types' ; 
9+ import  {  ITerminalManager ,   IWorkspaceService  }  from  '../application/types' ; 
1110import  '../extensions' ; 
1211import  {  traceDecorators ,  traceError  }  from  '../logger' ; 
1312import  {  IPlatformService  }  from  '../platform/types' ; 
1413import  {  IConfigurationService ,  ICurrentProcess ,  Resource  }  from  '../types' ; 
1514import  {  OSType  }  from  '../utils/platform' ; 
15+ import  {  ShellDetector  }  from  './shellDetector' ; 
1616import  {  ITerminalActivationCommandProvider ,  ITerminalHelper ,  TerminalActivationProviders ,  TerminalShellType  }  from  './types' ; 
1717
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- 
4018@injectable ( ) 
4119export  class  TerminalHelper  implements  ITerminalHelper  { 
42-  private  readonly  detectableShells :  Map < TerminalShellType ,   RegExp > ; 
20+  private  readonly  shellDetector :  ShellDetector ; 
4321 constructor ( @inject ( IPlatformService )  private  readonly  platform : IPlatformService , 
4422 @inject ( ITerminalManager )  private  readonly  terminalManager : ITerminalManager , 
4523 @inject ( ICondaService )  private  readonly  condaService : ICondaService , 
@@ -50,61 +28,17 @@ export class TerminalHelper implements ITerminalHelper {
5028 @inject ( ITerminalActivationCommandProvider )  @named ( TerminalActivationProviders . commandPromptAndPowerShell )  private  readonly  commandPromptAndPowerShell : ITerminalActivationCommandProvider , 
5129 @inject ( ITerminalActivationCommandProvider )  @named ( TerminalActivationProviders . pyenv )  private  readonly  pyenv : ITerminalActivationCommandProvider , 
5230 @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 
5433 )  { 
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+ 
6836 } 
6937 public  createTerminal ( title ?: string ) : Terminal  { 
7038 return  this . terminalManager . createTerminal ( {  name : title  } ) ; 
7139 } 
7240 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 ) ; 
10842 } 
10943
11044 public  buildCommandForTerminal ( terminalShellType : TerminalShellType ,  command : string ,  args : string [ ] )  { 
@@ -119,7 +53,10 @@ export class TerminalHelper implements ITerminalHelper {
11953 return  promise ; 
12054 } 
12155 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 ( ) ; 
12360 if  ( ! shell )  { 
12461 return ; 
12562 } 
@@ -181,30 +118,3 @@ export class TerminalHelper implements ITerminalHelper {
181118 } 
182119 } 
183120} 
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' }  ; 
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