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