2
2
// Distributed under the terms of the Modified BSD License.
3
3
4
4
import { ISettingRegistry } from '@jupyterlab/settingregistry' ;
5
+
5
6
import * as nbformat from '@jupyterlab/nbformat' ;
6
7
7
- import { DocumentRegistry } from '@jupyterlab/docregistry' ;
8
+ import {
9
+ IConsoleTracker ,
10
+ CodeConsole ,
11
+ ConsolePanel ,
12
+ } from '@jupyterlab/console' ;
8
13
9
14
import {
10
- INotebookModel ,
11
15
INotebookTracker ,
12
16
Notebook ,
13
17
NotebookPanel ,
@@ -30,11 +34,13 @@ import { filter } from '@lumino/algorithm';
30
34
31
35
import { DisposableDelegate } from '@lumino/disposable' ;
32
36
33
- import { AttachedProperty } from '@lumino/properties' ;
34
-
35
37
import { WidgetRenderer } from './renderer' ;
36
38
37
- import { WidgetManager , WIDGET_VIEW_MIMETYPE } from './manager' ;
39
+ import {
40
+ WidgetManager ,
41
+ WIDGET_VIEW_MIMETYPE ,
42
+ KernelWidgetManager ,
43
+ } from './manager' ;
38
44
39
45
import { OutputModel , OutputView , OUTPUT_WIDGET_VERSION } from './output' ;
40
46
@@ -48,6 +54,7 @@ import '@jupyter-widgets/base/css/index.css';
48
54
import '@jupyter-widgets/controls/css/widgets-base.css' ;
49
55
import { KernelMessage } from '@jupyterlab/services' ;
50
56
import { ITranslator , nullTranslator } from '@jupyterlab/translation' ;
57
+ import { ISessionContext } from '@jupyterlab/apputils' ;
51
58
52
59
const WIDGET_REGISTRY : base . IWidgetRegistryData [ ] = [ ] ;
53
60
@@ -59,7 +66,7 @@ const SETTINGS: WidgetManager.Settings = { saveState: false };
59
66
/**
60
67
* Iterate through all widget renderers in a notebook.
61
68
*/
62
- function * widgetRenderers (
69
+ function * notebookWidgetRenderers (
63
70
nb : Notebook
64
71
) : Generator < WidgetRenderer , void , unknown > {
65
72
for ( const cell of nb . widgets ) {
@@ -77,6 +84,25 @@ function* widgetRenderers(
77
84
}
78
85
}
79
86
87
+ /**
88
+ * Iterate through all widget renderers in a console.
89
+ */
90
+ function * consoleWidgetRenderers (
91
+ console : CodeConsole
92
+ ) : Generator < WidgetRenderer , void , unknown > {
93
+ for ( const cell of toArray ( console . cells ) ) {
94
+ if ( cell . model . type === 'code' ) {
95
+ for ( const codecell of ( cell as unknown as CodeCell ) . outputArea . widgets ) {
96
+ for ( const output of toArray ( codecell . children ( ) ) ) {
97
+ if ( output instanceof WidgetRenderer ) {
98
+ yield output ;
99
+ }
100
+ }
101
+ }
102
+ }
103
+ }
104
+ }
105
+
80
106
/**
81
107
* Iterate through all matching linked output views
82
108
*/
@@ -109,16 +135,69 @@ function* chain<T>(
109
135
}
110
136
}
111
137
112
- export function registerWidgetManager (
113
- context : DocumentRegistry . IContext < INotebookModel > ,
138
+ /**
139
+ * Get the kernel id of current notebook or console panel, this value
140
+ * is used as key for `Private.widgetManagerProperty` to store the widget
141
+ * manager of current notebook or console panel.
142
+ *
143
+ * @param {ISessionContext } sessionContext The session context of notebook or
144
+ * console panel.
145
+ */
146
+ async function getWidgetManagerOwner (
147
+ sessionContext : ISessionContext
148
+ ) : Promise < Private . IWidgetManagerOwner > {
149
+ await sessionContext . ready ;
150
+ return sessionContext . session ! . kernel ! . id ;
151
+ }
152
+
153
+ /**
154
+ * Common handler for registering both notebook and console
155
+ * `WidgetManager`
156
+ *
157
+ * @param {(Notebook | CodeConsole) } content Context of panel.
158
+ * @param {ISessionContext } sessionContext Session context of panel.
159
+ * @param {IRenderMimeRegistry } rendermime Rendermime of panel.
160
+ * @param {IterableIterator<WidgetRenderer> } renderers Iterator of
161
+ * `WidgetRenderer` inside panel
162
+ * @param {(() => WidgetManager | KernelWidgetManager) } widgetManagerFactory
163
+ * function to create widget manager.
164
+ */
165
+ async function registerWidgetHandler (
166
+ content : Notebook | CodeConsole ,
167
+ sessionContext : ISessionContext ,
114
168
rendermime : IRenderMimeRegistry ,
115
- renderers : IterableIterator < WidgetRenderer >
116
- ) : DisposableDelegate {
117
- let wManager = Private . widgetManagerProperty . get ( context ) ;
169
+ renderers : IterableIterator < WidgetRenderer > ,
170
+ widgetManagerFactory : ( ) => WidgetManager | KernelWidgetManager
171
+ ) : Promise < DisposableDelegate > {
172
+ const wManagerOwner = await getWidgetManagerOwner ( sessionContext ) ;
173
+ let wManager = Private . widgetManagerProperty . get ( wManagerOwner ) ;
174
+ let currentOwner : string ;
175
+
118
176
if ( ! wManager ) {
119
- wManager = new WidgetManager ( context , rendermime , SETTINGS ) ;
177
+ wManager = widgetManagerFactory ( ) ;
120
178
WIDGET_REGISTRY . forEach ( ( data ) => wManager ! . register ( data ) ) ;
121
- Private . widgetManagerProperty . set ( context , wManager ) ;
179
+ Private . widgetManagerProperty . set ( wManagerOwner , wManager ) ;
180
+ currentOwner = wManagerOwner ;
181
+ content . disposed . connect ( ( _ ) => {
182
+ const currentwManager = Private . widgetManagerProperty . get ( currentOwner ) ;
183
+ if ( currentwManager ) {
184
+ Private . widgetManagerProperty . delete ( currentOwner ) ;
185
+ }
186
+ } ) ;
187
+
188
+ sessionContext . kernelChanged . connect ( ( _ , args ) => {
189
+ const { newValue } = args ;
190
+ if ( newValue ) {
191
+ const newKernelId = newValue . id ;
192
+ const oldwManager = Private . widgetManagerProperty . get ( currentOwner ) ;
193
+
194
+ if ( oldwManager ) {
195
+ Private . widgetManagerProperty . delete ( currentOwner ) ;
196
+ Private . widgetManagerProperty . set ( newKernelId , oldwManager ) ;
197
+ }
198
+ currentOwner = newKernelId ;
199
+ }
200
+ } ) ;
122
201
}
123
202
124
203
for ( const r of renderers ) {
@@ -145,6 +224,45 @@ export function registerWidgetManager(
145
224
} ) ;
146
225
}
147
226
227
+ export async function registerWidgetManager (
228
+ panel : NotebookPanel ,
229
+ renderers : IterableIterator < WidgetRenderer >
230
+ ) : Promise < DisposableDelegate > {
231
+ const content = panel . content ;
232
+ const context = panel . context ;
233
+ const sessionContext = context . sessionContext ;
234
+ const rendermime = content . rendermime ;
235
+ const widgetManagerFactory = ( ) =>
236
+ new WidgetManager ( context , rendermime , SETTINGS ) ;
237
+
238
+ return registerWidgetHandler (
239
+ content ,
240
+ sessionContext ,
241
+ rendermime ,
242
+ renderers ,
243
+ widgetManagerFactory
244
+ ) ;
245
+ }
246
+
247
+ export async function registerConsoleWidgetManager (
248
+ panel : ConsolePanel ,
249
+ renderers : IterableIterator < WidgetRenderer >
250
+ ) : Promise < DisposableDelegate > {
251
+ const content = panel . console ;
252
+ const sessionContext = content . sessionContext ;
253
+ const rendermime = content . rendermime ;
254
+ const widgetManagerFactory = ( ) =>
255
+ new KernelWidgetManager ( sessionContext . session ! . kernel ! , rendermime ) ;
256
+
257
+ return registerWidgetHandler (
258
+ content ,
259
+ sessionContext ,
260
+ rendermime ,
261
+ renderers ,
262
+ widgetManagerFactory
263
+ ) ;
264
+ }
265
+
148
266
/**
149
267
* The widget manager provider.
150
268
*/
@@ -154,6 +272,7 @@ export const managerPlugin: JupyterFrontEndPlugin<base.IJupyterWidgetRegistry> =
154
272
requires : [ IRenderMimeRegistry ] ,
155
273
optional : [
156
274
INotebookTracker ,
275
+ IConsoleTracker ,
157
276
ISettingRegistry ,
158
277
IMainMenu ,
159
278
ILoggerRegistry ,
@@ -175,6 +294,7 @@ function activateWidgetExtension(
175
294
app : JupyterFrontEnd ,
176
295
rendermime : IRenderMimeRegistry ,
177
296
tracker : INotebookTracker | null ,
297
+ consoleTracker : IConsoleTracker | null ,
178
298
settingRegistry : ISettingRegistry | null ,
179
299
menu : IMainMenu | null ,
180
300
loggerRegistry : ILoggerRegistry | null ,
@@ -183,15 +303,23 @@ function activateWidgetExtension(
183
303
const { commands } = app ;
184
304
const trans = ( translator ?? nullTranslator ) . load ( 'jupyterlab_widgets' ) ;
185
305
186
- const bindUnhandledIOPubMessageSignal = ( nb : NotebookPanel ) : void => {
306
+ const bindUnhandledIOPubMessageSignal = async (
307
+ nb : NotebookPanel
308
+ ) : Promise < void > => {
187
309
if ( ! loggerRegistry ) {
188
310
return ;
189
311
}
312
+ const wManagerOwner = await getWidgetManagerOwner (
313
+ nb . context . sessionContext
314
+ ) ;
315
+ const wManager = Private . widgetManagerProperty . get ( wManagerOwner ) ;
190
316
191
- const wManager = Private . widgetManagerProperty . get ( nb . context ) ;
192
317
if ( wManager ) {
193
318
wManager . onUnhandledIOPubMessage . connect (
194
- ( sender : WidgetManager , msg : KernelMessage . IIOPubMessage ) => {
319
+ (
320
+ sender : WidgetManager | KernelWidgetManager ,
321
+ msg : KernelMessage . IIOPubMessage
322
+ ) => {
195
323
const logger = loggerRegistry . getLogger ( nb . context . path ) ;
196
324
let level : LogLevel = 'warning' ;
197
325
if (
@@ -233,32 +361,32 @@ function activateWidgetExtension(
233
361
) ;
234
362
235
363
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
- )
364
+ const rendererIterator = ( panel : NotebookPanel ) =>
365
+ chain (
366
+ notebookWidgetRenderers ( panel . content ) ,
367
+ outputViews ( app , panel . context . path )
244
368
) ;
245
-
369
+ tracker . forEach ( async ( panel ) => {
370
+ await registerWidgetManager ( panel , rendererIterator ( panel ) ) ;
246
371
bindUnhandledIOPubMessageSignal ( panel ) ;
247
372
} ) ;
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
-
373
+ tracker . widgetAdded . connect ( async ( sender , panel ) => {
374
+ await registerWidgetManager ( panel , rendererIterator ( panel ) ) ;
258
375
bindUnhandledIOPubMessageSignal ( panel ) ;
259
376
} ) ;
260
377
}
261
378
379
+ if ( consoleTracker !== null ) {
380
+ const rendererIterator = ( panel : ConsolePanel ) =>
381
+ chain ( consoleWidgetRenderers ( panel . console ) ) ;
382
+
383
+ consoleTracker . forEach ( async ( panel ) => {
384
+ await registerConsoleWidgetManager ( panel , rendererIterator ( panel ) ) ;
385
+ } ) ;
386
+ consoleTracker . widgetAdded . connect ( async ( sender , panel ) => {
387
+ await registerConsoleWidgetManager ( panel , rendererIterator ( panel ) ) ;
388
+ } ) ;
389
+ }
262
390
if ( settingRegistry !== null ) {
263
391
// Add a command for automatically saving (jupyter-)widget state.
264
392
commands . addCommand ( '@jupyter-widgets/jupyterlab-manager:saveWidgetState' , {
@@ -378,13 +506,23 @@ export default [
378
506
] ;
379
507
namespace Private {
380
508
/**
381
- * A private attached property for a widget manager .
509
+ * A type alias for keys of `widgetManagerProperty` .
382
510
*/
383
- export const widgetManagerProperty = new AttachedProperty <
384
- DocumentRegistry . Context ,
385
- WidgetManager | undefined
386
- > ( {
387
- name : 'widgetManager' ,
388
- create : ( owner : DocumentRegistry . Context ) : undefined => undefined ,
389
- } ) ;
511
+ export type IWidgetManagerOwner = string ;
512
+
513
+ /**
514
+ * A type alias for values of `widgetManagerProperty` .
515
+ */
516
+ export type IWidgetManagerValue =
517
+ | WidgetManager
518
+ | KernelWidgetManager
519
+ | undefined ;
520
+
521
+ /**
522
+ * A private map for a widget manager.
523
+ */
524
+ export const widgetManagerProperty = new Map <
525
+ IWidgetManagerOwner ,
526
+ IWidgetManagerValue
527
+ > ( ) ;
390
528
}
0 commit comments