@@ -50,6 +50,8 @@ export class LocalTerminalBackendContribution implements IWorkbenchContribution
50
50
class LocalTerminalBackend extends BaseTerminalBackend implements ITerminalBackend {
51
51
private readonly _ptys : Map < number , LocalPty > = new Map ( ) ;
52
52
53
+ private _ptyHostDirectProxy : IPtyService | undefined ;
54
+
53
55
private readonly _onDidRequestDetach = this . _register ( new Emitter < { requestId : number ; workspaceId : string ; instanceId : number } > ( ) ) ;
54
56
readonly onDidRequestDetach = this . _onDidRequestDetach . event ;
55
57
@@ -71,96 +73,100 @@ class LocalTerminalBackend extends BaseTerminalBackend implements ITerminalBacke
71
73
@IEnvironmentVariableService private readonly _environmentVariableService : IEnvironmentVariableService ,
72
74
@INotificationService notificationService : INotificationService ,
73
75
@IHistoryService historyService : IHistoryService ,
74
- @INativeWorkbenchEnvironmentService environmentService : INativeWorkbenchEnvironmentService
76
+ @INativeWorkbenchEnvironmentService private readonly _environmentService : INativeWorkbenchEnvironmentService
75
77
) {
76
78
super ( _localPtyService , logService , notificationService , historyService , _configurationResolverService , workspaceContextService ) ;
77
79
80
+ // TODO: If we connect async like this, there may be a race condition where messages go missing before the message port is established
81
+ this . _start ( ) ;
82
+ }
83
+
84
+ private async _start ( ) {
85
+
78
86
// TODO: Use the direct connection
79
- ( async ( ) => {
80
- mark ( 'code/willConnectPtyHost' ) ;
81
- logService . trace ( 'Renderer->PtyHost#connect: before acquirePort' ) ;
82
- const port = await acquirePort ( 'vscode:createPtyHostMessageChannel' , 'vscode:createPtyHostMessageChannelResult' ) ;
83
- mark ( 'code/didConnectPtyHost' ) ;
84
- logService . trace ( 'Renderer->PtyHost#connect: connection established' ) ;
85
-
86
- const client = new MessagePortClient ( port , `window:${ environmentService . window . id } ` ) ;
87
- const proxy = ProxyChannel . toService < IPtyService > ( client . getChannel ( TerminalIpcChannels . PtyHostWindow ) ) ;
88
-
89
- // Testing
90
- logService . info ( 'latency: ' , proxy . getLatency ( 0 ) ) ;
91
- proxy . onProcessData ( e => {
92
- logService . info ( 'message port process data: ' + e . event ) ;
93
- } ) ;
94
- } ) ( ) ;
87
+ mark ( 'code/willConnectPtyHost' ) ;
88
+ this . _logService . trace ( 'Renderer->PtyHost#connect: before acquirePort' ) ;
89
+ const port = await acquirePort ( 'vscode:createPtyHostMessageChannel' , 'vscode:createPtyHostMessageChannelResult' ) ;
90
+ mark ( 'code/didConnectPtyHost' ) ;
91
+ this . _logService . trace ( 'Renderer->PtyHost#connect: connection established' ) ;
92
+
93
+ const client = new MessagePortClient ( port , `window:${ this . _environmentService . window . id } ` ) ;
94
+ this . _ptyHostDirectProxy = ProxyChannel . toService < IPtyService > ( client . getChannel ( TerminalIpcChannels . PtyHostWindow ) ) ;
95
+
96
+ // Testing
97
+ // this._logService.info('latency: ', this._ptyHostDirectProxy.getLatency(0));
98
+ // this._ptyHostDirectProxy.onProcessData(e => {
99
+ // this._logService.info('message port process data: ' + e.event);
100
+ // });
95
101
96
102
// Attach process listeners
97
- this . _localPtyService . onProcessData ( e => this . _ptys . get ( e . id ) ?. handleData ( e . event ) ) ;
98
- this . _localPtyService . onDidChangeProperty ( e => this . _ptys . get ( e . id ) ?. handleDidChangeProperty ( e . property ) ) ;
99
- this . _localPtyService . onProcessExit ( e => {
103
+ this . _ptyHostDirectProxy ! . onProcessData ( e => this . _ptys . get ( e . id ) ?. handleData ( e . event ) ) ;
104
+ this . _ptyHostDirectProxy ! . onDidChangeProperty ( e => this . _ptys . get ( e . id ) ?. handleDidChangeProperty ( e . property ) ) ;
105
+ this . _ptyHostDirectProxy ! . onProcessExit ( e => {
100
106
const pty = this . _ptys . get ( e . id ) ;
101
107
if ( pty ) {
102
108
pty . handleExit ( e . event ) ;
103
109
this . _ptys . delete ( e . id ) ;
104
110
}
105
111
} ) ;
106
- this . _localPtyService . onProcessReady ( e => this . _ptys . get ( e . id ) ?. handleReady ( e . event ) ) ;
107
- this . _localPtyService . onProcessReplay ( e => this . _ptys . get ( e . id ) ?. handleReplay ( e . event ) ) ;
108
- this . _localPtyService . onProcessOrphanQuestion ( e => this . _ptys . get ( e . id ) ?. handleOrphanQuestion ( ) ) ;
109
- this . _localPtyService . onDidRequestDetach ( e => this . _onDidRequestDetach . fire ( e ) ) ;
112
+ this . _ptyHostDirectProxy ! . onProcessReady ( e => this . _ptys . get ( e . id ) ?. handleReady ( e . event ) ) ;
113
+ this . _ptyHostDirectProxy ! . onProcessReplay ( e => this . _ptys . get ( e . id ) ?. handleReplay ( e . event ) ) ;
114
+ this . _ptyHostDirectProxy ! . onProcessOrphanQuestion ( e => this . _ptys . get ( e . id ) ?. handleOrphanQuestion ( ) ) ;
115
+ this . _ptyHostDirectProxy ! . onDidRequestDetach ( e => this . _onDidRequestDetach . fire ( e ) ) ;
110
116
111
117
// Listen for config changes
112
- const initialConfig = configurationService . getValue < ITerminalConfiguration > ( TERMINAL_CONFIG_SECTION ) ;
118
+ const initialConfig = this . _configurationService . getValue < ITerminalConfiguration > ( TERMINAL_CONFIG_SECTION ) ;
113
119
for ( const match of Object . keys ( initialConfig . autoReplies ) ) {
114
120
// Ensure the reply is value
115
121
const reply = initialConfig . autoReplies [ match ] as string | null ;
116
122
if ( reply ) {
117
- this . _localPtyService . installAutoReply ( match , reply ) ;
123
+ this . _ptyHostDirectProxy ! . installAutoReply ( match , reply ) ;
118
124
}
119
125
}
120
126
// TODO: Could simplify update to a single call
121
- this . _register ( configurationService . onDidChangeConfiguration ( async e => {
127
+ this . _register ( this . _configurationService . onDidChangeConfiguration ( async e => {
122
128
if ( e . affectsConfiguration ( TerminalSettingId . AutoReplies ) ) {
123
- this . _localPtyService . uninstallAllAutoReplies ( ) ;
124
- const config = configurationService . getValue < ITerminalConfiguration > ( TERMINAL_CONFIG_SECTION ) ;
129
+ this . _ptyHostDirectProxy ! . uninstallAllAutoReplies ( ) ;
130
+ const config = this . _configurationService . getValue < ITerminalConfiguration > ( TERMINAL_CONFIG_SECTION ) ;
125
131
for ( const match of Object . keys ( config . autoReplies ) ) {
126
132
// Ensure the reply is value
127
133
const reply = config . autoReplies [ match ] as string | null ;
128
134
if ( reply ) {
129
- await this . _localPtyService . installAutoReply ( match , reply ) ;
135
+ await this . _ptyHostDirectProxy ! . installAutoReply ( match , reply ) ;
130
136
}
131
137
}
132
138
}
133
139
} ) ) ;
134
140
}
135
141
136
142
async requestDetachInstance ( workspaceId : string , instanceId : number ) : Promise < IProcessDetails | undefined > {
137
- return this . _localPtyService . requestDetachInstance ( workspaceId , instanceId ) ;
143
+ return this . _ptyHostDirectProxy ! . requestDetachInstance ( workspaceId , instanceId ) ;
138
144
}
139
145
140
146
async acceptDetachInstanceReply ( requestId : number , persistentProcessId ?: number ) : Promise < void > {
141
147
if ( ! persistentProcessId ) {
142
148
this . _logService . warn ( 'Cannot attach to feature terminals, custom pty terminals, or those without a persistentProcessId' ) ;
143
149
return ;
144
150
}
145
- return this . _localPtyService . acceptDetachInstanceReply ( requestId , persistentProcessId ) ;
151
+ return this . _ptyHostDirectProxy ! . acceptDetachInstanceReply ( requestId , persistentProcessId ) ;
146
152
}
147
153
148
154
async persistTerminalState ( ) : Promise < void > {
149
155
const ids = Array . from ( this . _ptys . keys ( ) ) ;
150
- const serialized = await this . _localPtyService . serializeTerminalState ( ids ) ;
156
+ const serialized = await this . _ptyHostDirectProxy ! . serializeTerminalState ( ids ) ;
151
157
this . _storageService . store ( TerminalStorageKeys . TerminalBufferState , serialized , StorageScope . WORKSPACE , StorageTarget . MACHINE ) ;
152
158
}
153
159
154
160
async updateTitle ( id : number , title : string , titleSource : TitleEventSource ) : Promise < void > {
155
- await this . _localPtyService . updateTitle ( id , title , titleSource ) ;
161
+ await this . _ptyHostDirectProxy ! . updateTitle ( id , title , titleSource ) ;
156
162
}
157
163
158
164
async updateIcon ( id : number , userInitiated : boolean , icon : URI | { light : URI ; dark : URI } | { id : string ; color ?: { id : string } } , color ?: string ) : Promise < void > {
159
- await this . _localPtyService . updateIcon ( id , userInitiated , icon , color ) ;
165
+ await this . _ptyHostDirectProxy ! . updateIcon ( id , userInitiated , icon , color ) ;
160
166
}
161
167
162
168
updateProperty < T extends ProcessPropertyType > ( id : number , property : ProcessPropertyType , value : IProcessPropertyMap [ T ] ) : Promise < void > {
163
- return this . _localPtyService . updateProperty ( id , property , value ) ;
169
+ return this . _ptyHostDirectProxy ! . updateProperty ( id , property , value ) ;
164
170
}
165
171
166
172
async createProcess (
@@ -174,15 +180,15 @@ class LocalTerminalBackend extends BaseTerminalBackend implements ITerminalBacke
174
180
shouldPersist : boolean
175
181
) : Promise < ITerminalChildProcess > {
176
182
const executableEnv = await this . _shellEnvironmentService . getShellEnv ( ) ;
177
- const id = await this . _localPtyService . createProcess ( shellLaunchConfig , cwd , cols , rows , unicodeVersion , env , executableEnv , options , shouldPersist , this . _getWorkspaceId ( ) , this . _getWorkspaceName ( ) ) ;
183
+ const id = await this . _ptyHostDirectProxy ! . createProcess ( shellLaunchConfig , cwd , cols , rows , unicodeVersion , env , executableEnv , options , shouldPersist , this . _getWorkspaceId ( ) , this . _getWorkspaceName ( ) ) ;
178
184
const pty = this . _instantiationService . createInstance ( LocalPty , id , shouldPersist ) ;
179
185
this . _ptys . set ( id , pty ) ;
180
186
return pty ;
181
187
}
182
188
183
189
async attachToProcess ( id : number ) : Promise < ITerminalChildProcess | undefined > {
184
190
try {
185
- await this . _localPtyService . attachToProcess ( id ) ;
191
+ await this . _ptyHostDirectProxy ! . attachToProcess ( id ) ;
186
192
const pty = this . _instantiationService . createInstance ( LocalPty , id , true ) ;
187
193
this . _ptys . set ( id , pty ) ;
188
194
return pty ;
@@ -194,7 +200,7 @@ class LocalTerminalBackend extends BaseTerminalBackend implements ITerminalBacke
194
200
195
201
async attachToRevivedProcess ( id : number ) : Promise < ITerminalChildProcess | undefined > {
196
202
try {
197
- const newId = await this . _localPtyService . getRevivedPtyNewId ( id ) ?? id ;
203
+ const newId = await this . _ptyHostDirectProxy ! . getRevivedPtyNewId ( id ) ?? id ;
198
204
return await this . attachToProcess ( newId ) ;
199
205
} catch ( e ) {
200
206
this . _logService . warn ( `Couldn't attach to process ${ e . message } ` ) ;
@@ -203,39 +209,40 @@ class LocalTerminalBackend extends BaseTerminalBackend implements ITerminalBacke
203
209
}
204
210
205
211
async listProcesses ( ) : Promise < IProcessDetails [ ] > {
206
- return this . _localPtyService . listProcesses ( ) ;
212
+ return this . _ptyHostDirectProxy ! . listProcesses ( ) ;
207
213
}
208
214
209
215
async reduceConnectionGraceTime ( ) : Promise < void > {
210
- this . _localPtyService . reduceConnectionGraceTime ( ) ;
216
+ this . _ptyHostDirectProxy ! . reduceConnectionGraceTime ( ) ;
211
217
}
212
218
213
219
async getDefaultSystemShell ( osOverride ?: OperatingSystem ) : Promise < string > {
214
- return this . _localPtyService . getDefaultSystemShell ( osOverride ) ;
220
+ return this . _ptyHostDirectProxy ! . getDefaultSystemShell ( osOverride ) ;
215
221
}
216
222
217
223
async getProfiles ( profiles : unknown , defaultProfile : unknown , includeDetectedProfiles ?: boolean ) {
224
+ // TODO: Differentiate interfaces of direct to pty host and pty host service (or just move them all to pty host)
218
225
return this . _localPtyService . getProfiles ?.( this . _workspaceContextService . getWorkspace ( ) . id , profiles , defaultProfile , includeDetectedProfiles ) || [ ] ;
219
226
}
220
227
221
228
async getEnvironment ( ) : Promise < IProcessEnvironment > {
222
- return this . _localPtyService . getEnvironment ( ) ;
229
+ return this . _ptyHostDirectProxy ! . getEnvironment ( ) ;
223
230
}
224
231
225
232
async getShellEnvironment ( ) : Promise < IProcessEnvironment > {
226
233
return this . _shellEnvironmentService . getShellEnv ( ) ;
227
234
}
228
235
229
236
async getWslPath ( original : string , direction : 'unix-to-win' | 'win-to-unix' ) : Promise < string > {
230
- return this . _localPtyService . getWslPath ( original , direction ) ;
237
+ return this . _ptyHostDirectProxy ! . getWslPath ( original , direction ) ;
231
238
}
232
239
233
240
async setTerminalLayoutInfo ( layoutInfo ?: ITerminalsLayoutInfoById ) : Promise < void > {
234
241
const args : ISetTerminalLayoutInfoArgs = {
235
242
workspaceId : this . _getWorkspaceId ( ) ,
236
243
tabs : layoutInfo ? layoutInfo . tabs : [ ]
237
244
} ;
238
- await this . _localPtyService . setTerminalLayoutInfo ( args ) ;
245
+ await this . _ptyHostDirectProxy ! . setTerminalLayoutInfo ( args ) ;
239
246
// Store in the storage service as well to be used when reviving processes as normally this
240
247
// is stored in memory on the pty host
241
248
this . _storageService . store ( TerminalStorageKeys . TerminalLayoutInfo , JSON . stringify ( args ) , StorageScope . WORKSPACE , StorageTarget . MACHINE ) ;
0 commit comments