@@ -8,7 +8,7 @@ import { IStringDictionary } from 'vs/base/common/collections';
8
8
import { Emitter , Event } from 'vs/base/common/event' ;
9
9
import * as glob from 'vs/base/common/glob' ;
10
10
import * as json from 'vs/base/common/json' ;
11
- import { Disposable , IDisposable , IReference } from 'vs/base/common/lifecycle' ;
11
+ import { Disposable , dispose , IDisposable , IReference } from 'vs/base/common/lifecycle' ;
12
12
import { LRUCache , Touch } from 'vs/base/common/map' ;
13
13
import * as Objects from 'vs/base/common/objects' ;
14
14
import { ValidationState , ValidationStatus } from 'vs/base/common/parsers' ;
@@ -53,7 +53,7 @@ import { ITaskExecuteResult, ITaskResolver, ITaskSummary, ITaskSystem, ITaskSyst
53
53
import { getTemplates as getTaskTemplates } from 'vs/workbench/contrib/tasks/common/taskTemplates' ;
54
54
55
55
import * as TaskConfig from '../common/taskConfiguration' ;
56
- import { TerminalTaskSystem } from './terminalTaskSystem' ;
56
+ import { terminalsNotReconnectedExitCode , TerminalTaskSystem } from './terminalTaskSystem' ;
57
57
58
58
import { IQuickInputService , IQuickPick , IQuickPickItem , IQuickPickSeparator , QuickPickInput } from 'vs/platform/quickinput/common/quickInput' ;
59
59
@@ -181,6 +181,11 @@ class TaskMap {
181
181
}
182
182
}
183
183
184
+ interface EventBarrier {
185
+ isOpen : boolean ;
186
+ queuedEvent ?: boolean ;
187
+ }
188
+
184
189
export abstract class AbstractTaskService extends Disposable implements ITaskService {
185
190
186
191
// private static autoDetectTelemetryName: string = 'taskServer.autoDetect';
@@ -195,6 +200,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
195
200
196
201
private static _nextHandle : number = 0 ;
197
202
203
+ private _reconnectionBarrier : EventBarrier = { isOpen : true } ;
204
+
198
205
private _tasksReconnected : boolean = false ;
199
206
private _schemaVersion : JsonSchemaVersion | undefined ;
200
207
private _executionEngine : ExecutionEngine | undefined ;
@@ -209,7 +216,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
209
216
protected _workspaceTasksPromise ?: Promise < Map < string , IWorkspaceFolderTaskResult > > ;
210
217
211
218
protected _taskSystem ?: ITaskSystem ;
212
- protected _taskSystemListener ?: IDisposable ;
219
+ protected _taskSystemListeners ?: IDisposable [ ] = [ ] ;
213
220
private _recentlyUsedTasksV1 : LRUCache < string , string > | undefined ;
214
221
private _recentlyUsedTasks : LRUCache < string , string > | undefined ;
215
222
@@ -219,6 +226,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
219
226
220
227
protected _outputChannel : IOutputChannel ;
221
228
protected readonly _onDidStateChange : Emitter < ITaskEvent > ;
229
+ protected readonly _onDidReconnectToTerminals : Emitter < void > = new Emitter ( ) ;
222
230
private _waitForSupportedExecutions : Promise < void > ;
223
231
private _onDidRegisterSupportedExecutions : Emitter < void > = new Emitter ( ) ;
224
232
private _onDidChangeTaskSystemInfo : Emitter < void > = new Emitter ( ) ;
@@ -265,7 +273,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
265
273
266
274
this . _workspaceTasksPromise = undefined ;
267
275
this . _taskSystem = undefined ;
268
- this . _taskSystemListener = undefined ;
276
+ this . _taskSystemListeners = undefined ;
269
277
this . _outputChannel = this . _outputService . getChannel ( AbstractTaskService . OutputChannelId ) ! ;
270
278
this . _providers = new Map < number , ITaskProvider > ( ) ;
271
279
this . _providerTypes = new Map < number , string > ( ) ;
@@ -283,6 +291,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
283
291
if ( ! this . _taskSystem && ! this . _workspaceTasksPromise ) {
284
292
return ;
285
293
}
294
+
286
295
if ( ! this . _taskSystem || this . _taskSystem instanceof TerminalTaskSystem ) {
287
296
this . _outputChannel . clear ( ) ;
288
297
}
@@ -328,6 +337,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
328
337
this . _waitForSupportedExecutions = new Promise ( resolve => {
329
338
once ( this . _onDidRegisterSupportedExecutions . event ) ( ( ) => resolve ( ) ) ;
330
339
} ) ;
340
+ this . _register ( this . onDidReconnectToTerminals ( async ( ) => await this . _attemptTaskReconnection ( ) ) ) ;
341
+ this . _register ( this . _onDidRegisterSupportedExecutions . event ( async ( ) => await this . _attemptTaskReconnection ( ) ) ) ;
331
342
this . _upgrade ( ) ;
332
343
}
333
344
@@ -346,43 +357,65 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
346
357
processContext . set ( process && ! isVirtual ) ;
347
358
}
348
359
this . _onDidRegisterSupportedExecutions . fire ( ) ;
349
- if ( this . _configurationService . getValue ( TaskSettingId . Reconnection ) === true && this . _jsonTasksSupported && ! this . _tasksReconnected ) {
350
- this . _reconnectTasks ( ) ;
360
+ }
361
+
362
+ private async _attemptTaskReconnection ( ) : Promise < void > {
363
+ if ( ! this . _reconnectionBarrier . isOpen ) {
364
+ this . _reconnectionBarrier . queuedEvent = true ;
365
+ return ;
366
+ }
367
+ this . _reconnectionBarrier . isOpen = false ;
368
+ if ( ! this . _taskSystem ) {
369
+ this . _logService . info ( 'getting task system before reconnection' ) ;
370
+ await this . _getTaskSystem ( ) ;
371
+ }
372
+ this . _logService . info ( `attempting task reconnection, jsonTasksSupported: ${ this . _jsonTasksSupported } , reconnection pending ${ ! this . _tasksReconnected } ` ) ;
373
+ if ( this . _configurationService . getValue ( TaskSettingId . Reconnection ) === true && ! this . _tasksReconnected ) {
374
+ this . _tasksReconnected = await this . _reconnectTasks ( ) ;
375
+ }
376
+ this . _reconnectionBarrier . isOpen = true ;
377
+ if ( this . _reconnectionBarrier . queuedEvent ) {
378
+ this . _reconnectionBarrier . queuedEvent = undefined ;
379
+ await this . _attemptTaskReconnection ( ) ;
351
380
}
352
381
}
353
382
354
- private async _reconnectTasks ( ) : Promise < void > {
383
+ private async _reconnectTasks ( ) : Promise < boolean > {
355
384
if ( this . _lifecycleService . startupKind !== StartupKind . ReloadedWindow ) {
356
385
this . _tasksReconnected = true ;
357
386
this . _storageService . remove ( AbstractTaskService . PersistentTasks_Key , StorageScope . WORKSPACE ) ;
358
- return ;
387
+ return true ;
359
388
}
360
389
const tasks = await this . getSavedTasks ( 'persistent' ) ;
361
- if ( ! this . _taskSystem ) {
362
- await this . _getTaskSystem ( ) ;
363
- }
364
390
if ( ! tasks . length ) {
365
- this . _tasksReconnected = true ;
366
- return ;
391
+ return true ;
367
392
}
368
-
369
393
for ( const task of tasks ) {
394
+ let result ;
370
395
if ( ConfiguringTask . is ( task ) ) {
371
396
const resolved = await this . tryResolveTask ( task ) ;
372
397
if ( resolved ) {
373
- this . run ( resolved , undefined , TaskRunSource . Reconnect ) ;
398
+ result = await this . run ( resolved , undefined , TaskRunSource . Reconnect ) ;
374
399
}
375
400
} else {
376
- this . run ( task , undefined , TaskRunSource . Reconnect ) ;
401
+ result = await this . run ( task , undefined , TaskRunSource . Reconnect ) ;
402
+ }
403
+ if ( result ?. exitCode === terminalsNotReconnectedExitCode ) {
404
+ this . _logService . trace ( 'Terminals were not reconnected' ) ;
405
+ return false ;
377
406
}
378
407
}
379
- this . _tasksReconnected = true ;
408
+ return true ;
380
409
}
381
410
382
411
public get onDidStateChange ( ) : Event < ITaskEvent > {
383
412
return this . _onDidStateChange . event ;
384
413
}
385
414
415
+ public get onDidReconnectToTerminals ( ) : Event < void > {
416
+ return this . _onDidReconnectToTerminals . event ;
417
+ }
418
+
386
419
public get supportsMultipleTaskExecutions ( ) : boolean {
387
420
return this . inTerminal ( ) ;
388
421
}
@@ -607,7 +640,10 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
607
640
}
608
641
609
642
protected _disposeTaskSystemListeners ( ) : void {
610
- this . _taskSystemListener ?. dispose ( ) ;
643
+ if ( this . _taskSystemListeners ) {
644
+ dispose ( this . _taskSystemListeners ) ;
645
+ this . _taskSystemListeners = undefined ;
646
+ }
611
647
}
612
648
613
649
public registerTaskProvider ( provider : ITaskProvider , type : string ) : IDisposable {
0 commit comments