2
2
// Distributed under the terms of the Modified BSD License.
3
3
4
4
import { ISettingRegistry } from '@jupyterlab/settingregistry' ;
5
- import * as nbformat from '@jupyterlab/nbformat' ;
6
5
7
6
import { DocumentRegistry } from '@jupyterlab/docregistry' ;
8
7
8
+ import * as nbformat from '@jupyterlab/nbformat' ;
9
+
10
+ import {
11
+ IConsoleTracker ,
12
+ CodeConsole ,
13
+ ConsolePanel ,
14
+ } from '@jupyterlab/console' ;
15
+
9
16
import {
10
17
INotebookModel ,
11
18
INotebookTracker ,
@@ -30,11 +37,13 @@ import { filter } from '@lumino/algorithm';
30
37
31
38
import { DisposableDelegate } from '@lumino/disposable' ;
32
39
33
- import { AttachedProperty } from '@lumino/properties' ;
34
-
35
40
import { WidgetRenderer } from './renderer' ;
36
41
37
- import { WidgetManager , WIDGET_VIEW_MIMETYPE } from './manager' ;
42
+ import {
43
+ WidgetManager ,
44
+ WIDGET_VIEW_MIMETYPE ,
45
+ KernelWidgetManager ,
46
+ } from './manager' ;
38
47
39
48
import { OutputModel , OutputView , OUTPUT_WIDGET_VERSION } from './output' ;
40
49
@@ -48,6 +57,7 @@ import '@jupyter-widgets/base/css/index.css';
48
57
import '@jupyter-widgets/controls/css/widgets-base.css' ;
49
58
import { KernelMessage } from '@jupyterlab/services' ;
50
59
import { ITranslator , nullTranslator } from '@jupyterlab/translation' ;
60
+ import { ISessionContext } from '@jupyterlab/apputils' ;
51
61
52
62
const WIDGET_REGISTRY : base . IWidgetRegistryData [ ] = [ ] ;
53
63
@@ -59,7 +69,7 @@ const SETTINGS: WidgetManager.Settings = { saveState: false };
59
69
/**
60
70
* Iterate through all widget renderers in a notebook.
61
71
*/
62
- function * widgetRenderers (
72
+ function * notebookWidgetRenderers (
63
73
nb : Notebook
64
74
) : Generator < WidgetRenderer , void , unknown > {
65
75
for ( const cell of nb . widgets ) {
@@ -77,6 +87,25 @@ function* widgetRenderers(
77
87
}
78
88
}
79
89
90
+ /**
91
+ * Iterate through all widget renderers in a console.
92
+ */
93
+ function * consoleWidgetRenderers (
94
+ console : CodeConsole
95
+ ) : Generator < WidgetRenderer , void , unknown > {
96
+ for ( const cell of Array . from ( console . cells ) ) {
97
+ if ( cell . model . type === 'code' ) {
98
+ for ( const codecell of ( cell as unknown as CodeCell ) . outputArea . widgets ) {
99
+ for ( const output of Array . from ( codecell . children ( ) ) ) {
100
+ if ( output instanceof WidgetRenderer ) {
101
+ yield output ;
102
+ }
103
+ }
104
+ }
105
+ }
106
+ }
107
+ }
108
+
80
109
/**
81
110
* Iterate through all matching linked output views
82
111
*/
@@ -109,16 +138,69 @@ function* chain<T>(
109
138
}
110
139
}
111
140
112
- export function registerWidgetManager (
113
- context : DocumentRegistry . IContext < INotebookModel > ,
141
+ /**
142
+ * Get the kernel id of current notebook or console panel, this value
143
+ * is used as key for `Private.widgetManagerProperty` to store the widget
144
+ * manager of current notebook or console panel.
145
+ *
146
+ * @param {ISessionContext } sessionContext The session context of notebook or
147
+ * console panel.
148
+ */
149
+ async function getWidgetManagerOwner (
150
+ sessionContext : ISessionContext
151
+ ) : Promise < Private . IWidgetManagerOwner > {
152
+ await sessionContext . ready ;
153
+ return sessionContext . session ! . kernel ! . id ;
154
+ }
155
+
156
+ /**
157
+ * Common handler for registering both notebook and console
158
+ * `WidgetManager`
159
+ *
160
+ * @param {(Notebook | CodeConsole) } content Context of panel.
161
+ * @param {ISessionContext } sessionContext Session context of panel.
162
+ * @param {IRenderMimeRegistry } rendermime Rendermime of panel.
163
+ * @param {IterableIterator<WidgetRenderer> } renderers Iterator of
164
+ * `WidgetRenderer` inside panel
165
+ * @param {(() => WidgetManager | KernelWidgetManager) } widgetManagerFactory
166
+ * function to create widget manager.
167
+ */
168
+ async function registerWidgetHandler (
169
+ content : Notebook | CodeConsole ,
170
+ sessionContext : ISessionContext ,
114
171
rendermime : IRenderMimeRegistry ,
115
- renderers : IterableIterator < WidgetRenderer >
116
- ) : DisposableDelegate {
117
- let wManager = Private . widgetManagerProperty . get ( context ) ;
172
+ renderers : IterableIterator < WidgetRenderer > ,
173
+ widgetManagerFactory : ( ) => WidgetManager | KernelWidgetManager
174
+ ) : Promise < DisposableDelegate > {
175
+ const wManagerOwner = await getWidgetManagerOwner ( sessionContext ) ;
176
+ let wManager = Private . widgetManagerProperty . get ( wManagerOwner ) ;
177
+ let currentOwner : string ;
178
+
118
179
if ( ! wManager ) {
119
- wManager = new WidgetManager ( context , rendermime , SETTINGS ) ;
180
+ wManager = widgetManagerFactory ( ) ;
120
181
WIDGET_REGISTRY . forEach ( ( data ) => wManager ! . register ( data ) ) ;
121
- Private . widgetManagerProperty . set ( context , wManager ) ;
182
+ Private . widgetManagerProperty . set ( wManagerOwner , wManager ) ;
183
+ currentOwner = wManagerOwner ;
184
+ content . disposed . connect ( ( _ ) => {
185
+ const currentwManager = Private . widgetManagerProperty . get ( currentOwner ) ;
186
+ if ( currentwManager ) {
187
+ Private . widgetManagerProperty . delete ( currentOwner ) ;
188
+ }
189
+ } ) ;
190
+
191
+ sessionContext . kernelChanged . connect ( ( _ , args ) => {
192
+ const { newValue } = args ;
193
+ if ( newValue ) {
194
+ const newKernelId = newValue . id ;
195
+ const oldwManager = Private . widgetManagerProperty . get ( currentOwner ) ;
196
+
197
+ if ( oldwManager ) {
198
+ Private . widgetManagerProperty . delete ( currentOwner ) ;
199
+ Private . widgetManagerProperty . set ( newKernelId , oldwManager ) ;
200
+ }
201
+ currentOwner = newKernelId ;
202
+ }
203
+ } ) ;
122
204
}
123
205
124
206
for ( const r of renderers ) {
@@ -145,6 +227,92 @@ export function registerWidgetManager(
145
227
} ) ;
146
228
}
147
229
230
+ // Kept for backward compat ipywidgets<=8, but not used here anymore
231
+ export function registerWidgetManager (
232
+ context : DocumentRegistry . IContext < INotebookModel > ,
233
+ rendermime : IRenderMimeRegistry ,
234
+ renderers : IterableIterator < WidgetRenderer >
235
+ ) : DisposableDelegate {
236
+ let wManager : WidgetManager ;
237
+ const managerReady = getWidgetManagerOwner ( context . sessionContext ) . then (
238
+ ( wManagerOwner ) => {
239
+ const currentManager = Private . widgetManagerProperty . get (
240
+ wManagerOwner
241
+ ) as WidgetManager ;
242
+ if ( ! currentManager ) {
243
+ wManager = new WidgetManager ( context , rendermime , SETTINGS ) ;
244
+ WIDGET_REGISTRY . forEach ( ( data ) => wManager ! . register ( data ) ) ;
245
+ Private . widgetManagerProperty . set ( wManagerOwner , wManager ) ;
246
+ } else {
247
+ wManager = currentManager ;
248
+ }
249
+
250
+ for ( const r of renderers ) {
251
+ r . manager = wManager ;
252
+ }
253
+
254
+ // Replace the placeholder widget renderer with one bound to this widget
255
+ // manager.
256
+ rendermime . removeMimeType ( WIDGET_VIEW_MIMETYPE ) ;
257
+ rendermime . addFactory (
258
+ {
259
+ safe : false ,
260
+ mimeTypes : [ WIDGET_VIEW_MIMETYPE ] ,
261
+ createRenderer : ( options ) => new WidgetRenderer ( options , wManager ) ,
262
+ } ,
263
+ - 10
264
+ ) ;
265
+ }
266
+ ) ;
267
+
268
+ return new DisposableDelegate ( async ( ) => {
269
+ await managerReady ;
270
+ if ( rendermime ) {
271
+ rendermime . removeMimeType ( WIDGET_VIEW_MIMETYPE ) ;
272
+ }
273
+ wManager ! . dispose ( ) ;
274
+ } ) ;
275
+ }
276
+
277
+ export async function registerNotebookWidgetManager (
278
+ panel : NotebookPanel ,
279
+ renderers : IterableIterator < WidgetRenderer >
280
+ ) : Promise < DisposableDelegate > {
281
+ const content = panel . content ;
282
+ const context = panel . context ;
283
+ const sessionContext = context . sessionContext ;
284
+ const rendermime = content . rendermime ;
285
+ const widgetManagerFactory = ( ) =>
286
+ new WidgetManager ( context , rendermime , SETTINGS ) ;
287
+
288
+ return registerWidgetHandler (
289
+ content ,
290
+ sessionContext ,
291
+ rendermime ,
292
+ renderers ,
293
+ widgetManagerFactory
294
+ ) ;
295
+ }
296
+
297
+ export async function registerConsoleWidgetManager (
298
+ panel : ConsolePanel ,
299
+ renderers : IterableIterator < WidgetRenderer >
300
+ ) : Promise < DisposableDelegate > {
301
+ const content = panel . console ;
302
+ const sessionContext = content . sessionContext ;
303
+ const rendermime = content . rendermime ;
304
+ const widgetManagerFactory = ( ) =>
305
+ new KernelWidgetManager ( sessionContext . session ! . kernel ! , rendermime ) ;
306
+
307
+ return registerWidgetHandler (
308
+ content ,
309
+ sessionContext ,
310
+ rendermime ,
311
+ renderers ,
312
+ widgetManagerFactory
313
+ ) ;
314
+ }
315
+
148
316
/**
149
317
* The widget manager provider.
150
318
*/
@@ -154,6 +322,7 @@ export const managerPlugin: JupyterFrontEndPlugin<base.IJupyterWidgetRegistry> =
154
322
requires : [ IRenderMimeRegistry ] ,
155
323
optional : [
156
324
INotebookTracker ,
325
+ IConsoleTracker ,
157
326
ISettingRegistry ,
158
327
IMainMenu ,
159
328
ILoggerRegistry ,
@@ -175,6 +344,7 @@ function activateWidgetExtension(
175
344
app : JupyterFrontEnd ,
176
345
rendermime : IRenderMimeRegistry ,
177
346
tracker : INotebookTracker | null ,
347
+ consoleTracker : IConsoleTracker | null ,
178
348
settingRegistry : ISettingRegistry | null ,
179
349
menu : IMainMenu | null ,
180
350
loggerRegistry : ILoggerRegistry | null ,
@@ -183,15 +353,23 @@ function activateWidgetExtension(
183
353
const { commands } = app ;
184
354
const trans = ( translator ?? nullTranslator ) . load ( 'jupyterlab_widgets' ) ;
185
355
186
- const bindUnhandledIOPubMessageSignal = ( nb : NotebookPanel ) : void => {
356
+ const bindUnhandledIOPubMessageSignal = async (
357
+ nb : NotebookPanel
358
+ ) : Promise < void > => {
187
359
if ( ! loggerRegistry ) {
188
360
return ;
189
361
}
362
+ const wManagerOwner = await getWidgetManagerOwner (
363
+ nb . context . sessionContext
364
+ ) ;
365
+ const wManager = Private . widgetManagerProperty . get ( wManagerOwner ) ;
190
366
191
- const wManager = Private . widgetManagerProperty . get ( nb . context ) ;
192
367
if ( wManager ) {
193
368
wManager . onUnhandledIOPubMessage . connect (
194
- ( sender : WidgetManager , msg : KernelMessage . IIOPubMessage ) => {
369
+ (
370
+ sender : WidgetManager | KernelWidgetManager ,
371
+ msg : KernelMessage . IIOPubMessage
372
+ ) => {
195
373
const logger = loggerRegistry . getLogger ( nb . context . path ) ;
196
374
let level : LogLevel = 'warning' ;
197
375
if (
@@ -233,32 +411,32 @@ function activateWidgetExtension(
233
411
) ;
234
412
235
413
if ( tracker !== null ) {
236
- tracker . forEach ( ( panel ) => {
237
- registerWidgetManager (
238
- panel . context ,
239
- panel . content . rendermime ,
240
- chain (
241
- widgetRenderers ( panel . content ) ,
242
- outputViews ( app , panel . context . path )
243
- )
414
+ const rendererIterator = ( panel : NotebookPanel ) =>
415
+ chain (
416
+ notebookWidgetRenderers ( panel . content ) ,
417
+ outputViews ( app , panel . context . path )
244
418
) ;
245
-
419
+ tracker . forEach ( async ( panel ) => {
420
+ await registerNotebookWidgetManager ( panel , rendererIterator ( panel ) ) ;
246
421
bindUnhandledIOPubMessageSignal ( panel ) ;
247
422
} ) ;
248
- tracker . widgetAdded . connect ( ( sender , panel ) => {
249
- registerWidgetManager (
250
- panel . context ,
251
- panel . content . rendermime ,
252
- chain (
253
- widgetRenderers ( panel . content ) ,
254
- outputViews ( app , panel . context . path )
255
- )
256
- ) ;
257
-
423
+ tracker . widgetAdded . connect ( async ( sender , panel ) => {
424
+ await registerNotebookWidgetManager ( panel , rendererIterator ( panel ) ) ;
258
425
bindUnhandledIOPubMessageSignal ( panel ) ;
259
426
} ) ;
260
427
}
261
428
429
+ if ( consoleTracker !== null ) {
430
+ const rendererIterator = ( panel : ConsolePanel ) =>
431
+ chain ( consoleWidgetRenderers ( panel . console ) ) ;
432
+
433
+ consoleTracker . forEach ( async ( panel ) => {
434
+ await registerConsoleWidgetManager ( panel , rendererIterator ( panel ) ) ;
435
+ } ) ;
436
+ consoleTracker . widgetAdded . connect ( async ( sender , panel ) => {
437
+ await registerConsoleWidgetManager ( panel , rendererIterator ( panel ) ) ;
438
+ } ) ;
439
+ }
262
440
if ( settingRegistry !== null ) {
263
441
// Add a command for automatically saving (jupyter-)widget state.
264
442
commands . addCommand ( '@jupyter-widgets/jupyterlab-manager:saveWidgetState' , {
@@ -378,13 +556,23 @@ export default [
378
556
] ;
379
557
namespace Private {
380
558
/**
381
- * A private attached property for a widget manager .
559
+ * A type alias for keys of `widgetManagerProperty` .
382
560
*/
383
- export const widgetManagerProperty = new AttachedProperty <
384
- DocumentRegistry . Context ,
385
- WidgetManager | undefined
386
- > ( {
387
- name : 'widgetManager' ,
388
- create : ( owner : DocumentRegistry . Context ) : undefined => undefined ,
389
- } ) ;
561
+ export type IWidgetManagerOwner = string ;
562
+
563
+ /**
564
+ * A type alias for values of `widgetManagerProperty` .
565
+ */
566
+ export type IWidgetManagerValue =
567
+ | WidgetManager
568
+ | KernelWidgetManager
569
+ | undefined ;
570
+
571
+ /**
572
+ * A private map for a widget manager.
573
+ */
574
+ export const widgetManagerProperty = new Map <
575
+ IWidgetManagerOwner ,
576
+ IWidgetManagerValue
577
+ > ( ) ;
390
578
}
0 commit comments