@@ -33,6 +33,7 @@ import { IConfigurationService, InteractiveWindowMode, IsWebExtension, Resource
33
33
import { noop } from '../platform/common/utils/misc' ;
34
34
import {
35
35
IKernel ,
36
+ IKernelProvider ,
36
37
isLocalConnection ,
37
38
KernelAction ,
38
39
KernelConnectionMetadata ,
@@ -42,7 +43,6 @@ import { chainable } from '../platform/common/utils/decorators';
42
43
import { InteractiveCellResultError } from '../platform/errors/interactiveCellResultError' ;
43
44
import { DataScience } from '../platform/common/utils/localize' ;
44
45
import { createDeferred , Deferred } from '../platform/common/utils/async' ;
45
- import { IServiceContainer } from '../platform/ioc/types' ;
46
46
import { SysInfoReason } from '../messageTypes' ;
47
47
import { createOutputWithErrorMessageForDisplay } from '../platform/errors/errorUtils' ;
48
48
import { INotebookExporter } from '../kernels/jupyter/types' ;
@@ -55,15 +55,13 @@ import {
55
55
IInteractiveWindowDebuggingManager ,
56
56
InteractiveTab
57
57
} from './types' ;
58
- import { generateInteractiveCode , isInteractiveInputTab } from './helpers' ;
58
+ import { generateInteractiveCode , getInteractiveCellMetadata , isInteractiveInputTab } from './helpers' ;
59
59
import {
60
60
IControllerRegistration ,
61
61
IControllerSelection ,
62
62
IVSCodeNotebookController
63
63
} from '../notebooks/controllers/types' ;
64
64
import { DisplayOptions } from '../kernels/displayOptions' ;
65
- import { getInteractiveCellMetadata } from './helpers' ;
66
- import { KernelConnector } from '../notebooks/controllers/kernelConnector' ;
67
65
import { getFilePath } from '../platform/common/platform/fs-paths' ;
68
66
import {
69
67
ICodeGeneratorFactory ,
@@ -76,6 +74,8 @@ import { updateNotebookMetadata } from '../kernels/execution/helpers';
76
74
import { chainWithPendingUpdates } from '../kernels/execution/notebookUpdater' ;
77
75
import { initializeInteractiveOrNotebookTelemetryBasedOnUserAction } from '../kernels/telemetry/helper' ;
78
76
import { generateMarkdownFromCodeLines , parseForComments } from '../platform/common/utils' ;
77
+ import { IServiceContainer } from '../platform/ioc/types' ;
78
+ import { KernelConnector } from '../notebooks/controllers/kernelConnector' ;
79
79
80
80
/**
81
81
* ViewModel for an interactive window from the Jupyter extension's point of view.
@@ -111,7 +111,8 @@ export class InteractiveWindow implements IInteractiveWindowLoadable {
111
111
private kernelDisposables : Disposable [ ] = [ ] ;
112
112
private _insertSysInfoPromise : Promise < NotebookCell > | undefined ;
113
113
private currentKernelInfo : {
114
- kernel ?: Deferred < IKernel > ;
114
+ kernelStarted ?: Deferred < void > ;
115
+ kernel ?: IKernel ;
115
116
controller ?: NotebookController ;
116
117
metadata ?: KernelConnectionMetadata ;
117
118
} = { } ;
@@ -141,6 +142,7 @@ export class InteractiveWindow implements IInteractiveWindowLoadable {
141
142
private readonly debuggingManager : IInteractiveWindowDebuggingManager ;
142
143
private readonly isWebExtension : boolean ;
143
144
private readonly commandManager : ICommandManager ;
145
+ private readonly kernelProvider : IKernelProvider ;
144
146
private readonly controllerRegistration : IControllerRegistration ;
145
147
constructor (
146
148
private readonly serviceContainer : IServiceContainer ,
@@ -163,6 +165,7 @@ export class InteractiveWindow implements IInteractiveWindowLoadable {
163
165
this . errorHandler = this . serviceContainer . get < IDataScienceErrorHandler > ( IDataScienceErrorHandler ) ;
164
166
this . codeGeneratorFactory = this . serviceContainer . get < ICodeGeneratorFactory > ( ICodeGeneratorFactory ) ;
165
167
this . storageFactory = this . serviceContainer . get < IGeneratedCodeStorageFactory > ( IGeneratedCodeStorageFactory ) ;
168
+ this . kernelProvider = this . serviceContainer . get < IKernelProvider > ( IKernelProvider ) ;
166
169
this . debuggingManager = this . serviceContainer . get < IInteractiveWindowDebuggingManager > (
167
170
IInteractiveWindowDebuggingManager
168
171
) ;
@@ -249,32 +252,40 @@ export class InteractiveWindow implements IInteractiveWindowLoadable {
249
252
// This cannot happen, but we need to make typescript happy.
250
253
throw new Error ( 'Controller not selected' ) ;
251
254
}
252
- if ( this . currentKernelInfo . kernel ) {
253
- return this . currentKernelInfo . kernel . promise ;
255
+ if ( this . currentKernelInfo . kernelStarted ) {
256
+ await this . currentKernelInfo . kernelStarted . promise ;
257
+ return this . currentKernelInfo . kernel ! ;
254
258
}
255
- const kernelPromise = createDeferred < IKernel > ( ) ;
256
- kernelPromise . promise . catch ( noop ) ;
257
- this . currentKernelInfo = { controller, metadata, kernel : kernelPromise } ;
259
+ const kernelStarted = createDeferred < void > ( ) ;
260
+ kernelStarted . promise . catch ( noop ) ;
261
+ this . currentKernelInfo = { controller, metadata, kernelStarted } ;
258
262
259
263
const sysInfoCell = this . insertSysInfoMessage ( metadata , SysInfoReason . Start ) ;
260
264
try {
261
265
// Try creating a kernel
262
266
initializeInteractiveOrNotebookTelemetryBasedOnUserAction ( this . owner , metadata ) ;
263
267
264
- const onStartKernel = ( action : KernelAction , k : IKernel ) => {
268
+ const onKernelStarted = async ( action : KernelAction , k : IKernel ) => {
265
269
if ( action !== 'start' && action !== 'restart' ) {
266
270
return ;
267
271
}
268
272
// Id may be different if the user switched controllers
269
- this . currentKernelInfo . controller = k . controller ;
270
- this . currentKernelInfo . metadata = k . kernelConnectionMetadata ;
273
+ this . currentKernelInfo . kernel = k ;
271
274
! ! this . pendingCellAdd && this . setPendingCellAdd ( this . pendingCellAdd ) ;
272
275
this . updateSysInfoMessage (
273
276
this . getSysInfoMessage ( k . kernelConnectionMetadata , SysInfoReason . Start ) ,
274
277
false ,
275
278
sysInfoCell
276
279
) ;
277
280
} ;
281
+ const onKernelStartCompleted = async ( action : KernelAction , _ : unknown , k : IKernel ) => {
282
+ if ( action !== 'start' && action !== 'restart' ) {
283
+ return ;
284
+ }
285
+ // Id may be different if the user switched controllers
286
+ this . currentKernelInfo . controller = k . controller ;
287
+ this . currentKernelInfo . metadata = k . kernelConnectionMetadata ;
288
+ } ;
278
289
// When connecting, we need to update the sys info message
279
290
this . updateSysInfoMessage ( this . getSysInfoMessage ( metadata , SysInfoReason . Start ) , false , sysInfoCell ) ;
280
291
const kernel = await KernelConnector . connectToNotebookKernel (
@@ -284,7 +295,8 @@ export class InteractiveWindow implements IInteractiveWindowLoadable {
284
295
new DisplayOptions ( false ) ,
285
296
this . internalDisposables ,
286
297
'jupyterExtension' ,
287
- onStartKernel
298
+ onKernelStarted ,
299
+ onKernelStartCompleted
288
300
) ;
289
301
this . currentKernelInfo . controller = kernel . controller ;
290
302
this . currentKernelInfo . metadata = kernel . kernelConnectionMetadata ;
@@ -324,10 +336,11 @@ export class InteractiveWindow implements IInteractiveWindowLoadable {
324
336
this . fileInKernel = undefined ;
325
337
await this . runInitialization ( kernel , this . owner ) ;
326
338
this . finishSysInfoMessage ( kernel , sysInfoCell , SysInfoReason . Start ) ;
327
- kernelPromise . resolve ( kernel ) ;
339
+ kernelStarted . resolve ( ) ;
328
340
return kernel ;
329
341
} catch ( ex ) {
330
- kernelPromise . reject ( ex ) ;
342
+ kernelStarted . reject ( ex ) ;
343
+ this . currentKernelInfo . kernelStarted = undefined ;
331
344
this . currentKernelInfo . kernel = undefined ;
332
345
this . disconnectKernel ( ) ;
333
346
if ( this . owner ) {
@@ -443,6 +456,7 @@ export class InteractiveWindow implements IInteractiveWindowLoadable {
443
456
message = message . split ( '\n' ) . join ( ' \n' ) ;
444
457
this . updateSysInfoMessage ( message , true , cellPromise ) ;
445
458
}
459
+
446
460
private listenForControllerSelection ( ) {
447
461
// Ensure we hear about any controller changes so we can update our cached promises
448
462
this . notebookControllerSelection . onControllerSelected (
@@ -452,7 +466,13 @@ export class InteractiveWindow implements IInteractiveWindowLoadable {
452
466
}
453
467
454
468
// Clear cached kernel when the selected controller for this document changes
455
- if ( e . controller . id !== this . currentKernelInfo . controller ?. id ) {
469
+ const kernel = this . kernelProvider . get ( this . notebookDocument . uri ) ;
470
+ const isControllerAttachedToTheSameKernel =
471
+ kernel && this . currentKernelInfo . kernel && kernel === this . currentKernelInfo . kernel ;
472
+ if (
473
+ e . controller . connection . id !== this . currentKernelInfo . kernel ?. kernelConnectionMetadata . id &&
474
+ ! isControllerAttachedToTheSameKernel
475
+ ) {
456
476
this . disconnectKernel ( ) ;
457
477
this . startKernel ( e . controller . controller , e . controller . connection ) . ignoreErrors ( ) ;
458
478
}
@@ -621,6 +641,7 @@ export class InteractiveWindow implements IInteractiveWindowLoadable {
621
641
private disconnectKernel ( ) {
622
642
this . kernelDisposables . forEach ( ( d ) => d . dispose ( ) ) ;
623
643
this . kernelDisposables = [ ] ;
644
+ this . currentKernelInfo . kernelStarted = undefined ;
624
645
this . currentKernelInfo . kernel = undefined ;
625
646
}
626
647
0 commit comments