44 *--------------------------------------------------------------------------------------------*/
55
66import * as nls from 'vs/nls' ;
7- import * as platform from 'vs/base/common/platform' ;
8- import * as cp from 'child_process' ;
97import { IDisposable } from 'vs/base/common/lifecycle' ;
108import { TPromise } from 'vs/base/common/winjs.base' ;
119import { ITerminalService , ITerminalInstance } from 'vs/workbench/parts/terminal/common/terminal' ;
1210import { ITerminalService as IExternalTerminalService } from 'vs/workbench/parts/execution/common/execution' ;
1311import { ITerminalLauncher , ITerminalSettings } from 'vs/workbench/parts/debug/common/debug' ;
12+ import { hasChildprocesses , prepareCommand } from 'vs/workbench/parts/debug/node/terminals' ;
1413
15- const enum ShellType { cmd , powershell , bash }
16-
17- export class TerminalLauncher implements ITerminalLauncher {
14+ export class AbstractTerminalLauncher implements ITerminalLauncher {
1815
1916 private integratedTerminalInstance : ITerminalInstance ;
2017 private terminalDisposedListener : IDisposable ;
2118
22- constructor (
23- @ITerminalService private terminalService : ITerminalService ,
24- @IExternalTerminalService private nativeTerminalService : IExternalTerminalService
25- ) {
19+ constructor ( private terminalService : ITerminalService ) {
2620 }
2721
28- runInTerminal ( args : DebugProtocol . RunInTerminalRequestArguments , config : ITerminalSettings ) : TPromise < void > {
22+ async runInTerminal ( args : DebugProtocol . RunInTerminalRequestArguments , config : ITerminalSettings ) : TPromise < void > {
2923
3024 if ( args . kind === 'external' ) {
31- return this . nativeTerminalService . runInTerminal ( args . title , args . cwd , args . args , args . env || { } ) ;
25+ return this . runInExternalTerminal ( args , config ) ;
3226 }
3327
3428 if ( ! this . terminalDisposedListener ) {
@@ -41,14 +35,14 @@ export class TerminalLauncher implements ITerminalLauncher {
4135 }
4236
4337 let t = this . integratedTerminalInstance ;
44- if ( ( t && this . isBusy ( t ) ) || ! t ) {
38+ if ( ( t && await this . isBusy ( t . processId ) ) || ! t ) {
4539 t = this . terminalService . createTerminal ( { name : args . title || nls . localize ( 'debug.terminal.title' , "debuggee" ) } ) ;
4640 this . integratedTerminalInstance = t ;
4741 }
4842 this . terminalService . setActiveInstance ( t ) ;
4943 this . terminalService . showPanel ( true ) ;
5044
51- const command = this . prepareCommand ( args , config ) ;
45+ const command = await this . prepareCommand ( args , config ) ;
5246
5347 return new TPromise ( ( resolve , error ) => {
5448 setTimeout ( _ => {
@@ -58,158 +52,29 @@ export class TerminalLauncher implements ITerminalLauncher {
5852 } ) ;
5953 }
6054
61- private isBusy ( t : ITerminalInstance ) : boolean {
62- if ( t . processId ) {
63- try {
64- // if shell has at least one child process, assume that shell is busy
65- if ( platform . isWindows ) {
66- const result = cp . spawnSync ( 'wmic' , [ 'process' , 'get' , 'ParentProcessId' ] ) ;
67- if ( result . stdout ) {
68- const pids = result . stdout . toString ( ) . split ( '\r\n' ) ;
69- if ( ! pids . some ( p => parseInt ( p ) === t . processId ) ) {
70- return false ;
71- }
72- }
73- } else {
74- const result = cp . spawnSync ( '/usr/bin/pgrep' , [ '-lP' , String ( t . processId ) ] ) ;
75- if ( result . stdout ) {
76- const r = result . stdout . toString ( ) . trim ( ) ;
77- if ( r . length === 0 || r . indexOf ( ' tmux' ) >= 0 ) { // ignore 'tmux'; see #43683
78- return false ;
79- }
80- }
81- }
82- }
83- catch ( e ) {
84- // silently ignore
85- }
86- }
87- // fall back to safe side
88- return true ;
55+ protected runInExternalTerminal ( args : DebugProtocol . RunInTerminalRequestArguments , config : ITerminalSettings ) : TPromise < void > {
56+ return void 0 ;
8957 }
9058
91- private prepareCommand ( args : DebugProtocol . RunInTerminalRequestArguments , config : ITerminalSettings ) : string {
92-
93- let shellType : ShellType ;
94-
95- // get the shell configuration for the current platform
96- let shell : string ;
97- const shell_config = config . integrated . shell ;
98- if ( platform . isWindows ) {
99- shell = shell_config . windows ;
100- shellType = ShellType . cmd ;
101- } else if ( platform . isLinux ) {
102- shell = shell_config . linux ;
103- shellType = ShellType . bash ;
104- } else if ( platform . isMacintosh ) {
105- shell = shell_config . osx ;
106- shellType = ShellType . bash ;
107- }
108-
109- // try to determine the shell type
110- shell = shell . trim ( ) . toLowerCase ( ) ;
111- if ( shell . indexOf ( 'powershell' ) >= 0 ) {
112- shellType = ShellType . powershell ;
113- } else if ( shell . indexOf ( 'cmd.exe' ) >= 0 ) {
114- shellType = ShellType . cmd ;
115- } else if ( shell . indexOf ( 'bash' ) >= 0 ) {
116- shellType = ShellType . bash ;
117- } else if ( shell . indexOf ( 'git\\bin\\bash.exe' ) >= 0 ) {
118- shellType = ShellType . bash ;
119- }
120-
121- let quote : ( s : string ) => string ;
122- let command = '' ;
123-
124- switch ( shellType ) {
125-
126- case ShellType . powershell :
127-
128- quote = ( s : string ) => {
129- s = s . replace ( / \' / g, '\'\'' ) ;
130- return `'${ s } '` ;
131- //return s.indexOf(' ') >= 0 || s.indexOf('\'') >= 0 || s.indexOf('"') >= 0 ? `'${s}'` : s;
132- } ;
133-
134- if ( args . cwd ) {
135- command += `cd '${ args . cwd } '; ` ;
136- }
137- if ( args . env ) {
138- for ( let key in args . env ) {
139- const value = args . env [ key ] ;
140- if ( value === null ) {
141- command += `Remove-Item env:${ key } ; ` ;
142- } else {
143- command += `\${env:${ key } }='${ value } '; ` ;
144- }
145- }
146- }
147- if ( args . args && args . args . length > 0 ) {
148- const cmd = quote ( args . args . shift ( ) ) ;
149- command += ( cmd [ 0 ] === '\'' ) ? `& ${ cmd } ` : `${ cmd } ` ;
150- for ( let a of args . args ) {
151- command += `${ quote ( a ) } ` ;
152- }
153- }
154- break ;
155-
156- case ShellType . cmd :
157-
158- quote = ( s : string ) => {
159- s = s . replace ( / \" / g, '""' ) ;
160- return ( s . indexOf ( ' ' ) >= 0 || s . indexOf ( '"' ) >= 0 ) ? `"${ s } "` : s ;
161- } ;
162-
163- if ( args . cwd ) {
164- command += `cd ${ quote ( args . cwd ) } && ` ;
165- }
166- if ( args . env ) {
167- command += 'cmd /C "' ;
168- for ( let key in args . env ) {
169- const value = args . env [ key ] ;
170- if ( value === null ) {
171- command += `set "${ key } =" && ` ;
172- } else {
173- command += `set "${ key } =${ args . env [ key ] } " && ` ;
174- }
175- }
176- }
177- for ( let a of args . args ) {
178- command += `${ quote ( a ) } ` ;
179- }
180- if ( args . env ) {
181- command += '"' ;
182- }
183- break ;
59+ protected isBusy ( processId : number ) : TPromise < boolean > {
60+ return TPromise . as ( hasChildprocesses ( processId ) ) ;
61+ }
18462
185- case ShellType . bash :
63+ protected prepareCommand ( args : DebugProtocol . RunInTerminalRequestArguments , config : ITerminalSettings ) : TPromise < string > {
64+ return TPromise . as ( prepareCommand ( args , config ) ) ;
65+ }
66+ }
18667
187- quote = ( s : string ) => {
188- s = s . replace ( / \" / g, '\\"' ) ;
189- return ( s . indexOf ( ' ' ) >= 0 || s . indexOf ( '\\' ) >= 0 ) ? `"${ s } "` : s ;
190- } ;
68+ export class TerminalLauncher extends AbstractTerminalLauncher {
19169
192- if ( args . cwd ) {
193- command += `cd ${ quote ( args . cwd ) } ; ` ;
194- }
195- if ( args . env ) {
196- command += 'env' ;
197- for ( let key in args . env ) {
198- const value = args . env [ key ] ;
199- if ( value === null ) {
200- command += ` -u "${ key } "` ;
201- } else {
202- command += ` "${ key } =${ value } "` ;
203- }
204- }
205- command += ' ' ;
206- }
207- for ( let a of args . args ) {
208- command += `${ quote ( a ) } ` ;
209- }
210- break ;
211- }
70+ constructor (
71+ @ITerminalService terminalService : ITerminalService ,
72+ @IExternalTerminalService private nativeTerminalService : IExternalTerminalService
73+ ) {
74+ super ( terminalService ) ;
75+ }
21276
213- return command ;
77+ runInExternalTerminal ( args : DebugProtocol . RunInTerminalRequestArguments , config : ITerminalSettings ) : TPromise < void > {
78+ return this . nativeTerminalService . runInTerminal ( args . title , args . cwd , args . args , args . env || { } ) ;
21479 }
21580}
0 commit comments