@@ -50,6 +50,8 @@ import { EnhancedPreviewWidget } from '@theia/core/lib/browser/widgets/enhanced-
50
50
import { MarkdownRenderer , MarkdownRendererFactory } from '@theia/core/lib/browser/markdown-rendering/markdown-renderer' ;
51
51
import { RemoteConnectionProvider , ServiceConnectionProvider } from '@theia/core/lib/browser/messaging/service-connection-provider' ;
52
52
import { ColorRegistry } from '@theia/core/lib/browser/color-registry' ;
53
+ import { GeneralShellType , WindowsShellType } from '../common/terminal' ;
54
+ import * as path from 'path' ;
53
55
54
56
export const TERMINAL_WIDGET_FACTORY_ID = 'terminal' ;
55
57
@@ -157,6 +159,9 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
157
159
protected readonly onMouseLeaveLinkHoverEmitter = new Emitter < MouseEvent > ( ) ;
158
160
readonly onMouseLeaveLinkHover : Event < MouseEvent > = this . onMouseLeaveLinkHoverEmitter . event ;
159
161
162
+ protected readonly onShellTypeChangedEmiter = new Emitter < string > ( ) ;
163
+ readonly onShellTypeChanged : Event < string > = this . onShellTypeChangedEmiter . event ;
164
+
160
165
protected readonly toDisposeOnConnect = new DisposableCollection ( ) ;
161
166
162
167
private _buffer : TerminalBuffer ;
@@ -260,6 +265,7 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
260
265
this . toDispose . push ( this . onSizeChangedEmitter ) ;
261
266
this . toDispose . push ( this . onDataEmitter ) ;
262
267
this . toDispose . push ( this . onKeyEmitter ) ;
268
+ this . toDispose . push ( this . onShellTypeChangedEmiter ) ;
263
269
264
270
const touchEndListener = ( event : TouchEvent ) => {
265
271
if ( this . node . contains ( event . target as Node ) ) {
@@ -589,7 +595,6 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
589
595
rootURI = root ?. resource ?. toString ( ) ;
590
596
}
591
597
const { cols, rows } = this . term ;
592
-
593
598
const terminalId = await this . shellTerminalServer . create ( {
594
599
shell : this . options . shellPath || this . shellPreferences . shell [ OS . backend . type ( ) ] ,
595
600
args : this . options . shellArgs || this . shellPreferences . shellArgs [ OS . backend . type ( ) ] ,
@@ -601,6 +606,11 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
601
606
rows
602
607
} ) ;
603
608
if ( IBaseTerminalServer . validateId ( terminalId ) ) {
609
+ const processInfo = await this . shellTerminalServer . getProcessInfo ( terminalId ) ;
610
+ const shellType = guessShellTypeFromExecutable ( processInfo . executable ) ;
611
+ if ( shellType ) {
612
+ this . onShellTypeChangedEmiter . fire ( shellType ) ;
613
+ }
604
614
return terminalId ;
605
615
}
606
616
throw new Error ( 'Error creating terminal widget, see the backend error log for more information.' ) ;
@@ -675,7 +685,7 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
675
685
const waitForConnection = this . waitForConnection = new Deferred < Channel > ( ) ;
676
686
this . connectionProvider . listen (
677
687
`${ terminalsPath } /${ this . terminalId } ` ,
678
- ( path , connection ) => {
688
+ ( _path , connection ) => {
679
689
connection . onMessage ( e => {
680
690
this . write ( e ( ) . readString ( ) ) ;
681
691
} ) ;
@@ -995,3 +1005,44 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
995
1005
return this . enhancedPreviewNode ;
996
1006
}
997
1007
}
1008
+
1009
+ function guessShellTypeFromExecutable ( executable : string | undefined ) : string | undefined {
1010
+ if ( ! executable ) {
1011
+ return undefined ;
1012
+ }
1013
+
1014
+ const executableName = path . basename ( executable ) ;
1015
+ // windows tested first, as gitbash may be confused with other OS bash
1016
+ if ( OS . backend . isWindows ) {
1017
+ const windowShellTypesToRegex : Map < string , RegExp > = new Map ( [
1018
+ [ WindowsShellType . CommandPrompt , / ^ c m d $ / ] ,
1019
+ [ WindowsShellType . GitBash , / ^ b a s h $ / ] ,
1020
+ [ WindowsShellType . Wsl , / ^ w s l $ / ]
1021
+ ] ) ;
1022
+ for ( const [ shellType , pattern ] of windowShellTypesToRegex ) {
1023
+ if ( executableName . match ( pattern ) ) {
1024
+ return shellType ;
1025
+ }
1026
+ }
1027
+ }
1028
+
1029
+ const shellTypesToRegex : Map < string , RegExp > = new Map ( [
1030
+ [ GeneralShellType . Bash , / ^ b a s h $ / ] ,
1031
+ [ GeneralShellType . Csh , / ^ c s h $ / ] ,
1032
+ [ GeneralShellType . Fish , / ^ f i s h $ / ] ,
1033
+ [ GeneralShellType . Julia , / ^ j u l i a $ / ] ,
1034
+ [ GeneralShellType . Ksh , / ^ k s h $ / ] ,
1035
+ [ GeneralShellType . Node , / ^ n o d e $ / ] ,
1036
+ [ GeneralShellType . NuShell , / ^ n u $ / ] ,
1037
+ [ GeneralShellType . PowerShell , / ^ p w s h ( - p r e v i e w ) ? | p o w e r s h e l l $ / ] ,
1038
+ [ GeneralShellType . Python , / ^ p y (?: t h o n ) ? $ / ] ,
1039
+ [ GeneralShellType . Sh , / ^ s h $ / ] ,
1040
+ [ GeneralShellType . Zsh , / ^ z s h $ / ]
1041
+ ] ) ;
1042
+ for ( const [ shellType , pattern ] of shellTypesToRegex ) {
1043
+ if ( executableName . match ( pattern ) ) {
1044
+ return shellType ;
1045
+ }
1046
+ }
1047
+ return undefined ;
1048
+ }
0 commit comments