@@ -20,6 +20,7 @@ import {
20
20
ITerminalService ,
21
21
TerminalCreationOptions ,
22
22
TerminalShellType ,
23
+ ITerminalExecutedCommand ,
23
24
} from './types' ;
24
25
25
26
@injectable ( )
@@ -32,6 +33,7 @@ export class TerminalService implements ITerminalService, Disposable {
32
33
private terminalActivator : ITerminalActivator ;
33
34
private terminalAutoActivator : ITerminalAutoActivation ;
34
35
private readonly envVarScript = path . join ( EXTENSION_ROOT_DIR , 'python_files' , 'pythonrc.py' ) ;
36
+ private readonly executeCommandListeners : Set < Disposable > = new Set ( ) ;
35
37
public get onDidCloseTerminal ( ) : Event < void > {
36
38
return this . terminalClosed . event . bind ( this . terminalClosed ) ;
37
39
}
@@ -48,8 +50,12 @@ export class TerminalService implements ITerminalService, Disposable {
48
50
this . terminalActivator = this . serviceContainer . get < ITerminalActivator > ( ITerminalActivator ) ;
49
51
}
50
52
public dispose ( ) {
51
- if ( this . terminal ) {
52
- this . terminal . dispose ( ) ;
53
+ this . terminal ?. dispose ( ) ;
54
+
55
+ if ( this . executeCommandListeners && this . executeCommandListeners . size > 0 ) {
56
+ this . executeCommandListeners . forEach ( ( d ) => {
57
+ d ?. dispose ( ) ;
58
+ } ) ;
53
59
}
54
60
}
55
61
public async sendCommand ( command : string , args : string [ ] , _ ?: CancellationToken ) : Promise < void > {
@@ -59,21 +65,67 @@ export class TerminalService implements ITerminalService, Disposable {
59
65
this . terminal ! . show ( true ) ;
60
66
}
61
67
62
- this . terminal ! . sendText ( text , true ) ;
68
+ await this . executeCommand ( text ) ;
63
69
}
70
+ /** @deprecated */
64
71
public async sendText ( text : string ) : Promise < void > {
65
72
await this . ensureTerminal ( ) ;
66
73
if ( ! this . options ?. hideFromUser ) {
67
74
this . terminal ! . show ( true ) ;
68
75
}
69
76
this . terminal ! . sendText ( text ) ;
70
77
}
78
+ public async executeCommand ( commandLine : string ) : Promise < ITerminalExecutedCommand | undefined > {
79
+ const terminal = this . terminal ! ;
80
+ if ( ! this . options ?. hideFromUser ) {
81
+ terminal . show ( true ) ;
82
+ }
83
+
84
+ // If terminal was just launched, wait some time for shell integration to onDidChangeShellIntegration.
85
+ if ( ! terminal . shellIntegration ) {
86
+ const promise = new Promise < boolean > ( ( resolve ) => {
87
+ const shellIntegrationChangeEventListener = this . terminalManager . onDidChangeTerminalShellIntegration (
88
+ ( ) => {
89
+ this . executeCommandListeners . delete ( shellIntegrationChangeEventListener ) ;
90
+ resolve ( true ) ;
91
+ } ,
92
+ ) ;
93
+ const TIMEOUT_DURATION = 3000 ;
94
+ setTimeout ( ( ) => {
95
+ this . executeCommandListeners . add ( shellIntegrationChangeEventListener ) ;
96
+ resolve ( true ) ;
97
+ } , TIMEOUT_DURATION ) ;
98
+ } ) ;
99
+ await promise ;
100
+ }
101
+
102
+ if ( terminal . shellIntegration ) {
103
+ const execution = terminal . shellIntegration . executeCommand ( commandLine ) ;
104
+ return await new Promise ( ( resolve ) => {
105
+ const listener = this . terminalManager . onDidEndTerminalShellExecution ( ( e ) => {
106
+ if ( e . execution === execution ) {
107
+ this . executeCommandListeners . delete ( listener ) ;
108
+ resolve ( { execution, exitCode : e . exitCode } ) ;
109
+ }
110
+ } ) ;
111
+ if ( listener ) {
112
+ this . executeCommandListeners . add ( listener ) ;
113
+ }
114
+ } ) ;
115
+ } else {
116
+ terminal . sendText ( commandLine ) ;
117
+ }
118
+
119
+ return undefined ;
120
+ }
121
+
71
122
public async show ( preserveFocus : boolean = true ) : Promise < void > {
72
123
await this . ensureTerminal ( preserveFocus ) ;
73
124
if ( ! this . options ?. hideFromUser ) {
74
125
this . terminal ! . show ( preserveFocus ) ;
75
126
}
76
127
}
128
+ // TODO: Debt switch to Promise<Terminal> ---> breaks 20 tests
77
129
public async ensureTerminal ( preserveFocus : boolean = true ) : Promise < void > {
78
130
if ( this . terminal ) {
79
131
return ;
@@ -89,18 +141,19 @@ export class TerminalService implements ITerminalService, Disposable {
89
141
// Sometimes the terminal takes some time to start up before it can start accepting input.
90
142
await new Promise ( ( resolve ) => setTimeout ( resolve , 100 ) ) ;
91
143
92
- await this . terminalActivator . activateEnvironmentInTerminal ( this . terminal ! , {
144
+ await this . terminalActivator . activateEnvironmentInTerminal ( this . terminal , {
93
145
resource : this . options ?. resource ,
94
146
preserveFocus,
95
147
interpreter : this . options ?. interpreter ,
96
148
hideFromUser : this . options ?. hideFromUser ,
97
149
} ) ;
98
150
99
151
if ( ! this . options ?. hideFromUser ) {
100
- this . terminal ! . show ( preserveFocus ) ;
152
+ this . terminal . show ( preserveFocus ) ;
101
153
}
102
154
103
155
this . sendTelemetry ( ) . ignoreErrors ( ) ;
156
+ return ;
104
157
}
105
158
private terminalCloseHandler ( terminal : Terminal ) {
106
159
if ( terminal === this . terminal ) {
0 commit comments