@jupyterlab/debugger 4.0.0-alpha.9 → 4.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/lib/debugger.d.ts +3 -1
  2. package/lib/debugger.js +5 -3
  3. package/lib/debugger.js.map +1 -1
  4. package/lib/dialogs/evaluate.d.ts +5 -0
  5. package/lib/dialogs/evaluate.js +16 -6
  6. package/lib/dialogs/evaluate.js.map +1 -1
  7. package/lib/factory.d.ts +1 -1
  8. package/lib/factory.js +15 -9
  9. package/lib/factory.js.map +1 -1
  10. package/lib/handler.js +15 -7
  11. package/lib/handler.js.map +1 -1
  12. package/lib/handlers/console.js +9 -3
  13. package/lib/handlers/console.js.map +1 -1
  14. package/lib/handlers/editor.d.ts +26 -12
  15. package/lib/handlers/editor.js +166 -89
  16. package/lib/handlers/editor.js.map +1 -1
  17. package/lib/handlers/file.js +6 -2
  18. package/lib/handlers/file.js.map +1 -1
  19. package/lib/handlers/notebook.d.ts +0 -7
  20. package/lib/handlers/notebook.js +11 -17
  21. package/lib/handlers/notebook.js.map +1 -1
  22. package/lib/icons.d.ts +2 -1
  23. package/lib/icons.js +6 -1
  24. package/lib/icons.js.map +1 -1
  25. package/lib/model.js +1 -0
  26. package/lib/model.js.map +1 -1
  27. package/lib/panels/breakpoints/index.d.ts +2 -2
  28. package/lib/panels/breakpoints/index.js +9 -7
  29. package/lib/panels/breakpoints/index.js.map +1 -1
  30. package/lib/panels/breakpoints/pauseonexceptions.d.ts +53 -0
  31. package/lib/panels/breakpoints/pauseonexceptions.js +98 -0
  32. package/lib/panels/breakpoints/pauseonexceptions.js.map +1 -0
  33. package/lib/panels/callstack/index.d.ts +1 -1
  34. package/lib/panels/kernelSources/body.d.ts +5 -7
  35. package/lib/panels/kernelSources/body.js +37 -47
  36. package/lib/panels/kernelSources/body.js.map +1 -1
  37. package/lib/panels/kernelSources/filter.d.ts +1 -2
  38. package/lib/panels/kernelSources/filter.js +2 -2
  39. package/lib/panels/kernelSources/filter.js.map +1 -1
  40. package/lib/panels/kernelSources/index.js +1 -1
  41. package/lib/panels/kernelSources/index.js.map +1 -1
  42. package/lib/panels/kernelSources/model.d.ts +10 -1
  43. package/lib/panels/kernelSources/model.js +19 -1
  44. package/lib/panels/kernelSources/model.js.map +1 -1
  45. package/lib/panels/sources/body.js +5 -3
  46. package/lib/panels/sources/body.js.map +1 -1
  47. package/lib/panels/sources/sourcepath.js +1 -1
  48. package/lib/panels/sources/sourcepath.js.map +1 -1
  49. package/lib/panels/variables/grid.d.ts +23 -10
  50. package/lib/panels/variables/grid.js +42 -367
  51. package/lib/panels/variables/grid.js.map +1 -1
  52. package/lib/panels/variables/gridpanel.d.ts +138 -0
  53. package/lib/panels/variables/gridpanel.js +362 -0
  54. package/lib/panels/variables/gridpanel.js.map +1 -0
  55. package/lib/panels/variables/mimerenderer.js +9 -1
  56. package/lib/panels/variables/mimerenderer.js.map +1 -1
  57. package/lib/panels/variables/scope.js +4 -0
  58. package/lib/panels/variables/scope.js.map +1 -1
  59. package/lib/panels/variables/tree.d.ts +1 -0
  60. package/lib/panels/variables/tree.js +136 -47
  61. package/lib/panels/variables/tree.js.map +1 -1
  62. package/lib/service.d.ts +20 -6
  63. package/lib/service.js +84 -59
  64. package/lib/service.js.map +1 -1
  65. package/lib/session.d.ts +20 -6
  66. package/lib/session.js +59 -11
  67. package/lib/session.js.map +1 -1
  68. package/lib/sidebar.js +1 -1
  69. package/lib/sources.d.ts +2 -2
  70. package/lib/sources.js +32 -17
  71. package/lib/sources.js.map +1 -1
  72. package/lib/tokens.d.ts +57 -13
  73. package/lib/tokens.js.map +1 -1
  74. package/package.json +38 -46
  75. package/src/config.ts +78 -0
  76. package/src/debugger.ts +154 -0
  77. package/src/dialogs/evaluate.ts +144 -0
  78. package/src/factory.ts +72 -0
  79. package/src/handler.ts +528 -0
  80. package/src/handlers/console.ts +118 -0
  81. package/src/handlers/editor.ts +469 -0
  82. package/src/handlers/file.ts +86 -0
  83. package/src/handlers/notebook.ts +128 -0
  84. package/src/hash.ts +69 -0
  85. package/src/icons.ts +64 -0
  86. package/src/index.ts +16 -0
  87. package/src/model.ts +155 -0
  88. package/src/panels/breakpoints/body.tsx +145 -0
  89. package/src/panels/breakpoints/index.ts +116 -0
  90. package/src/panels/breakpoints/model.ts +74 -0
  91. package/src/panels/breakpoints/pauseonexceptions.tsx +141 -0
  92. package/src/panels/callstack/body.tsx +96 -0
  93. package/src/panels/callstack/index.ts +152 -0
  94. package/src/panels/callstack/model.ts +86 -0
  95. package/src/panels/kernelSources/body.tsx +139 -0
  96. package/src/panels/kernelSources/filter.tsx +44 -0
  97. package/src/panels/kernelSources/index.tsx +106 -0
  98. package/src/panels/kernelSources/model.ts +160 -0
  99. package/src/panels/sources/body.ts +161 -0
  100. package/src/panels/sources/index.tsx +85 -0
  101. package/src/panels/sources/model.ts +94 -0
  102. package/src/panels/sources/sourcepath.tsx +31 -0
  103. package/src/panels/variables/grid.ts +145 -0
  104. package/src/panels/variables/gridpanel.ts +453 -0
  105. package/src/panels/variables/index.ts +199 -0
  106. package/src/panels/variables/mimerenderer.ts +125 -0
  107. package/src/panels/variables/model.ts +61 -0
  108. package/src/panels/variables/scope.tsx +132 -0
  109. package/src/panels/variables/tree.tsx +521 -0
  110. package/src/service.ts +1009 -0
  111. package/src/session.ts +342 -0
  112. package/src/sidebar.ts +194 -0
  113. package/src/sources.ts +327 -0
  114. package/src/svg.d.ts +9 -0
  115. package/src/tokens.ts +1071 -0
  116. package/style/breakpoints.css +21 -12
  117. package/style/callstack.css +2 -2
  118. package/style/icons/exceptions.svg +10 -0
  119. package/style/index.css +1 -1
  120. package/style/index.js +1 -1
  121. package/style/kernelSources.css +3 -9
  122. package/style/sources.css +1 -1
  123. package/style/variables.css +68 -21
package/src/handler.ts ADDED
@@ -0,0 +1,528 @@
1
+ // Copyright (c) Jupyter Development Team.
2
+ // Distributed under the terms of the Modified BSD License.
3
+
4
+ import { JupyterFrontEnd } from '@jupyterlab/application';
5
+ import { ISessionContext, SessionContext } from '@jupyterlab/apputils';
6
+ import { ConsolePanel } from '@jupyterlab/console';
7
+ import { IChangedArgs } from '@jupyterlab/coreutils';
8
+ import { DocumentWidget } from '@jupyterlab/docregistry';
9
+ import { FileEditor } from '@jupyterlab/fileeditor';
10
+ import { NotebookPanel } from '@jupyterlab/notebook';
11
+ import { Kernel, KernelMessage, Session } from '@jupyterlab/services';
12
+ import { ITranslator, nullTranslator } from '@jupyterlab/translation';
13
+ import { bugDotIcon, bugIcon, ToolbarButton } from '@jupyterlab/ui-components';
14
+ import { Debugger } from './debugger';
15
+ import { ConsoleHandler } from './handlers/console';
16
+ import { FileHandler } from './handlers/file';
17
+ import { NotebookHandler } from './handlers/notebook';
18
+ import { IDebugger } from './tokens';
19
+
20
+ const TOOLBAR_DEBUGGER_ITEM = 'debugger-icon';
21
+
22
+ /**
23
+ * Add a bug icon to the widget toolbar to enable and disable debugging.
24
+ *
25
+ * @param widget The widget to add the debug toolbar button to.
26
+ * @param onClick The callback when the toolbar button is clicked.
27
+ */
28
+ function updateIconButton(
29
+ widget: DebuggerHandler.SessionWidget[DebuggerHandler.SessionType],
30
+ onClick: () => void,
31
+ enabled?: boolean,
32
+ pressed?: boolean,
33
+ translator: ITranslator = nullTranslator
34
+ ): ToolbarButton {
35
+ const trans = translator.load('jupyterlab');
36
+ const icon = new ToolbarButton({
37
+ className: 'jp-DebuggerBugButton',
38
+ icon: bugIcon,
39
+ tooltip: trans.__('Enable Debugger'),
40
+ pressedIcon: bugDotIcon,
41
+ pressedTooltip: trans.__('Disable Debugger'),
42
+ disabledTooltip: trans.__(
43
+ 'Select a kernel that supports debugging to enable debugger'
44
+ ),
45
+ enabled,
46
+ pressed,
47
+ onClick
48
+ });
49
+ if (!widget.toolbar.insertBefore('kernelName', TOOLBAR_DEBUGGER_ITEM, icon)) {
50
+ widget.toolbar.addItem(TOOLBAR_DEBUGGER_ITEM, icon);
51
+ }
52
+
53
+ return icon;
54
+ }
55
+
56
+ /**
57
+ * Updates button state to on/off,
58
+ * adds/removes css class to update styling
59
+ *
60
+ * @param widget the debug button widget
61
+ * @param pressed true if pressed, false otherwise
62
+ * @param enabled true if widget enabled, false otherwise
63
+ * @param onClick click handler
64
+ */
65
+ function updateIconButtonState(
66
+ widget: ToolbarButton,
67
+ pressed: boolean,
68
+ enabled: boolean = true,
69
+ onClick?: () => void
70
+ ) {
71
+ if (widget) {
72
+ widget.enabled = enabled;
73
+ widget.pressed = pressed;
74
+ if (onClick) {
75
+ widget.onClick = onClick;
76
+ }
77
+ }
78
+ }
79
+
80
+ /**
81
+ * A handler for debugging a widget.
82
+ */
83
+ export class DebuggerHandler implements DebuggerHandler.IHandler {
84
+ /**
85
+ * Instantiate a new DebuggerHandler.
86
+ *
87
+ * @param options The instantiation options for a DebuggerHandler.
88
+ */
89
+ constructor(options: DebuggerHandler.IOptions) {
90
+ this._type = options.type;
91
+ this._shell = options.shell;
92
+ this._service = options.service;
93
+ }
94
+
95
+ /**
96
+ * Get the active widget.
97
+ */
98
+ get activeWidget():
99
+ | DebuggerHandler.SessionWidget[DebuggerHandler.SessionType]
100
+ | null {
101
+ return this._activeWidget;
102
+ }
103
+
104
+ /**
105
+ * Update a debug handler for the given widget, and
106
+ * handle kernel changed events.
107
+ *
108
+ * @param widget The widget to update.
109
+ * @param connection The session connection.
110
+ */
111
+ async update(
112
+ widget: DebuggerHandler.SessionWidget[DebuggerHandler.SessionType],
113
+ connection: Session.ISessionConnection | null
114
+ ): Promise<void> {
115
+ if (!connection) {
116
+ delete this._kernelChangedHandlers[widget.id];
117
+ delete this._statusChangedHandlers[widget.id];
118
+ delete this._iopubMessageHandlers[widget.id];
119
+ return this.updateWidget(widget, connection);
120
+ }
121
+
122
+ const kernelChanged = (): void => {
123
+ void this.updateWidget(widget, connection);
124
+ };
125
+ const kernelChangedHandler = this._kernelChangedHandlers[widget.id];
126
+
127
+ if (kernelChangedHandler) {
128
+ connection.kernelChanged.disconnect(kernelChangedHandler);
129
+ }
130
+ this._kernelChangedHandlers[widget.id] = kernelChanged;
131
+ connection.kernelChanged.connect(kernelChanged);
132
+
133
+ const statusChanged = (
134
+ _: Session.ISessionConnection,
135
+ status: Kernel.Status
136
+ ): void => {
137
+ if (status.endsWith('restarting')) {
138
+ void this.updateWidget(widget, connection);
139
+ }
140
+ };
141
+ const statusChangedHandler = this._statusChangedHandlers[widget.id];
142
+ if (statusChangedHandler) {
143
+ connection.statusChanged.disconnect(statusChangedHandler);
144
+ }
145
+ connection.statusChanged.connect(statusChanged);
146
+ this._statusChangedHandlers[widget.id] = statusChanged;
147
+
148
+ const iopubMessage = (
149
+ _: Session.ISessionConnection,
150
+ msg: KernelMessage.IIOPubMessage
151
+ ): void => {
152
+ if (
153
+ (msg.parent_header as KernelMessage.IHeader).msg_type ==
154
+ 'execute_request' &&
155
+ this._service.isStarted &&
156
+ !this._service.hasStoppedThreads()
157
+ ) {
158
+ void this._service.displayDefinedVariables();
159
+ }
160
+ };
161
+ const iopubMessageHandler = this._iopubMessageHandlers[widget.id];
162
+ if (iopubMessageHandler) {
163
+ connection.iopubMessage.disconnect(iopubMessageHandler);
164
+ }
165
+ connection.iopubMessage.connect(iopubMessage);
166
+ this._iopubMessageHandlers[widget.id] = iopubMessage;
167
+ this._activeWidget = widget;
168
+
169
+ return this.updateWidget(widget, connection);
170
+ }
171
+
172
+ /**
173
+ * Update a debug handler for the given widget, and
174
+ * handle connection kernel changed events.
175
+ *
176
+ * @param widget The widget to update.
177
+ * @param sessionContext The session context.
178
+ */
179
+ async updateContext(
180
+ widget: DebuggerHandler.SessionWidget[DebuggerHandler.SessionType],
181
+ sessionContext: ISessionContext
182
+ ): Promise<void> {
183
+ const connectionChanged = (): void => {
184
+ const { session: connection } = sessionContext;
185
+ void this.update(widget, connection);
186
+ };
187
+
188
+ const contextKernelChangedHandlers =
189
+ this._contextKernelChangedHandlers[widget.id];
190
+
191
+ if (contextKernelChangedHandlers) {
192
+ sessionContext.kernelChanged.disconnect(contextKernelChangedHandlers);
193
+ }
194
+ this._contextKernelChangedHandlers[widget.id] = connectionChanged;
195
+ sessionContext.kernelChanged.connect(connectionChanged);
196
+
197
+ return this.update(widget, sessionContext.session);
198
+ }
199
+
200
+ /**
201
+ * Update a debug handler for the given widget.
202
+ *
203
+ * @param widget The widget to update.
204
+ * @param connection The session connection.
205
+ */
206
+ async updateWidget(
207
+ widget: DebuggerHandler.SessionWidget[DebuggerHandler.SessionType],
208
+ connection: Session.ISessionConnection | null
209
+ ): Promise<void> {
210
+ if (!this._service.model || !connection) {
211
+ return;
212
+ }
213
+
214
+ const hasFocus = (): boolean => {
215
+ return this._shell.currentWidget === widget;
216
+ };
217
+
218
+ const updateAttribute = (): void => {
219
+ if (!this._handlers[widget.id]) {
220
+ widget.node.removeAttribute('data-jp-debugger');
221
+ return;
222
+ }
223
+ widget.node.setAttribute('data-jp-debugger', 'true');
224
+ };
225
+
226
+ const createHandler = (): void => {
227
+ if (this._handlers[widget.id]) {
228
+ return;
229
+ }
230
+
231
+ switch (this._type) {
232
+ case 'notebook':
233
+ this._handlers[widget.id] = new NotebookHandler({
234
+ debuggerService: this._service,
235
+ widget: widget as NotebookPanel
236
+ });
237
+ break;
238
+ case 'console':
239
+ this._handlers[widget.id] = new ConsoleHandler({
240
+ debuggerService: this._service,
241
+ widget: widget as ConsolePanel
242
+ });
243
+ break;
244
+ case 'file':
245
+ this._handlers[widget.id] = new FileHandler({
246
+ debuggerService: this._service,
247
+ widget: widget as DocumentWidget<FileEditor>
248
+ });
249
+ break;
250
+ default:
251
+ throw Error(`No handler for the type ${this._type}`);
252
+ }
253
+ updateAttribute();
254
+ };
255
+
256
+ const removeHandlers = (): void => {
257
+ const handler = this._handlers[widget.id];
258
+ if (!handler) {
259
+ return;
260
+ }
261
+ handler.dispose();
262
+ delete this._handlers[widget.id];
263
+ delete this._kernelChangedHandlers[widget.id];
264
+ delete this._statusChangedHandlers[widget.id];
265
+ delete this._iopubMessageHandlers[widget.id];
266
+ delete this._contextKernelChangedHandlers[widget.id];
267
+
268
+ // Clear the model if the handler being removed corresponds
269
+ // to the current active debug session, or if the connection
270
+ // does not have a kernel.
271
+ if (
272
+ this._service.session?.connection?.path === connection?.path ||
273
+ !this._service.session?.connection?.kernel
274
+ ) {
275
+ const model = this._service.model;
276
+ model.clear();
277
+ }
278
+
279
+ updateAttribute();
280
+ };
281
+
282
+ const addToolbarButton = (enabled: boolean = true): void => {
283
+ const debugButton = this._iconButtons[widget.id];
284
+ if (!debugButton) {
285
+ this._iconButtons[widget.id] = updateIconButton(
286
+ widget,
287
+ toggleDebugging,
288
+ this._service.isStarted,
289
+ enabled
290
+ );
291
+ } else {
292
+ updateIconButtonState(
293
+ debugButton,
294
+ this._service.isStarted,
295
+ enabled,
296
+ toggleDebugging
297
+ );
298
+ }
299
+ };
300
+
301
+ const isDebuggerOn = (): boolean => {
302
+ return (
303
+ this._service.isStarted &&
304
+ this._previousConnection?.id === connection?.id
305
+ );
306
+ };
307
+
308
+ const stopDebugger = async (): Promise<void> => {
309
+ this._service.session!.connection = connection;
310
+ await this._service.stop();
311
+ };
312
+
313
+ const startDebugger = async (): Promise<void> => {
314
+ this._service.session!.connection = connection;
315
+ this._previousConnection = connection;
316
+ await this._service.restoreState(true);
317
+ await this._service.displayDefinedVariables();
318
+ if (this._service.session?.capabilities?.supportsModulesRequest) {
319
+ await this._service.displayModules();
320
+ }
321
+ };
322
+
323
+ const toggleDebugging = async (): Promise<void> => {
324
+ // bail if the widget doesn't have focus
325
+ if (!hasFocus()) {
326
+ return;
327
+ }
328
+ const debugButton = this._iconButtons[widget.id]!;
329
+ if (isDebuggerOn()) {
330
+ await stopDebugger();
331
+ removeHandlers();
332
+ updateIconButtonState(debugButton, false);
333
+ } else {
334
+ await startDebugger();
335
+ createHandler();
336
+ updateIconButtonState(debugButton, true);
337
+ }
338
+ };
339
+
340
+ addToolbarButton(false);
341
+
342
+ // listen to the disposed signals
343
+ widget.disposed.connect(async () => {
344
+ if (isDebuggerOn()) {
345
+ await stopDebugger();
346
+ }
347
+ removeHandlers();
348
+ delete this._iconButtons[widget.id];
349
+ delete this._contextKernelChangedHandlers[widget.id];
350
+ });
351
+
352
+ const debuggingEnabled = await this._service.isAvailable(connection);
353
+ if (!debuggingEnabled) {
354
+ removeHandlers();
355
+ updateIconButtonState(this._iconButtons[widget.id]!, false, false);
356
+ return;
357
+ }
358
+
359
+ // update the active debug session
360
+ if (!this._service.session) {
361
+ this._service.session = new Debugger.Session({
362
+ connection,
363
+ config: this._service.config
364
+ });
365
+ } else {
366
+ this._previousConnection = this._service.session!.connection?.kernel
367
+ ? this._service.session.connection
368
+ : null;
369
+ this._service.session.connection = connection;
370
+ }
371
+ await this._service.restoreState(false);
372
+ if (this._service.isStarted && !this._service.hasStoppedThreads()) {
373
+ await this._service.displayDefinedVariables();
374
+ if (this._service.session?.capabilities?.supportsModulesRequest) {
375
+ await this._service.displayModules();
376
+ }
377
+ }
378
+
379
+ updateIconButtonState(
380
+ this._iconButtons[widget.id]!,
381
+ this._service.isStarted,
382
+ true
383
+ );
384
+
385
+ // check the state of the debug session
386
+ if (!this._service.isStarted) {
387
+ removeHandlers();
388
+ this._service.session.connection = this._previousConnection ?? connection;
389
+ await this._service.restoreState(false);
390
+ return;
391
+ }
392
+
393
+ // if the debugger is started but there is no handler, create a new one
394
+ createHandler();
395
+ this._previousConnection = connection;
396
+ }
397
+
398
+ private _type: DebuggerHandler.SessionType;
399
+ private _shell: JupyterFrontEnd.IShell;
400
+ private _service: IDebugger;
401
+ private _previousConnection: Session.ISessionConnection | null;
402
+ private _activeWidget:
403
+ | DebuggerHandler.SessionWidget[DebuggerHandler.SessionType]
404
+ | null;
405
+ private _handlers: {
406
+ [id: string]: DebuggerHandler.SessionHandler[DebuggerHandler.SessionType];
407
+ } = {};
408
+
409
+ private _contextKernelChangedHandlers: {
410
+ [id: string]: (
411
+ sender: SessionContext,
412
+ args: IChangedArgs<
413
+ Kernel.IKernelConnection,
414
+ Kernel.IKernelConnection,
415
+ 'kernel'
416
+ >
417
+ ) => void;
418
+ } = {};
419
+ private _kernelChangedHandlers: {
420
+ [id: string]: (
421
+ sender: Session.ISessionConnection,
422
+ args: IChangedArgs<
423
+ Kernel.IKernelConnection,
424
+ Kernel.IKernelConnection,
425
+ 'kernel'
426
+ >
427
+ ) => void;
428
+ } = {};
429
+ private _statusChangedHandlers: {
430
+ [id: string]: (
431
+ sender: Session.ISessionConnection,
432
+ status: Kernel.Status
433
+ ) => void;
434
+ } = {};
435
+ private _iopubMessageHandlers: {
436
+ [id: string]: (
437
+ sender: Session.ISessionConnection,
438
+ msg: KernelMessage.IIOPubMessage
439
+ ) => void;
440
+ } = {};
441
+ private _iconButtons: {
442
+ [id: string]: ToolbarButton | undefined;
443
+ } = {};
444
+ }
445
+
446
+ /**
447
+ * A namespace for DebuggerHandler `statics`
448
+ */
449
+ export namespace DebuggerHandler {
450
+ /**
451
+ * Instantiation options for a DebuggerHandler.
452
+ */
453
+ export interface IOptions {
454
+ /**
455
+ * The type of session.
456
+ */
457
+ type: SessionType;
458
+
459
+ /**
460
+ * The application shell.
461
+ */
462
+ shell: JupyterFrontEnd.IShell;
463
+
464
+ /**
465
+ * The debugger service.
466
+ */
467
+ service: IDebugger;
468
+ }
469
+
470
+ /**
471
+ * An interface for debugger handler.
472
+ */
473
+ export interface IHandler {
474
+ /**
475
+ * Get the active widget.
476
+ */
477
+ activeWidget:
478
+ | DebuggerHandler.SessionWidget[DebuggerHandler.SessionType]
479
+ | null;
480
+
481
+ /**
482
+ * Update a debug handler for the given widget, and
483
+ * handle kernel changed events.
484
+ *
485
+ * @param widget The widget to update.
486
+ * @param connection The session connection.
487
+ */
488
+ update(
489
+ widget: DebuggerHandler.SessionWidget[DebuggerHandler.SessionType],
490
+ connection: Session.ISessionConnection | null
491
+ ): Promise<void>;
492
+
493
+ /**
494
+ * Update a debug handler for the given widget, and
495
+ * handle connection kernel changed events.
496
+ *
497
+ * @param widget The widget to update.
498
+ * @param sessionContext The session context.
499
+ */
500
+ updateContext(
501
+ widget: DebuggerHandler.SessionWidget[DebuggerHandler.SessionType],
502
+ sessionContext: ISessionContext
503
+ ): Promise<void>;
504
+ }
505
+
506
+ /**
507
+ * The types of sessions that can be debugged.
508
+ */
509
+ export type SessionType = keyof SessionHandler;
510
+
511
+ /**
512
+ * The types of handlers.
513
+ */
514
+ export type SessionHandler = {
515
+ notebook: NotebookHandler;
516
+ console: ConsoleHandler;
517
+ file: FileHandler;
518
+ };
519
+
520
+ /**
521
+ * The types of widgets that can be debugged.
522
+ */
523
+ export type SessionWidget = {
524
+ notebook: NotebookPanel;
525
+ console: ConsolePanel;
526
+ file: DocumentWidget;
527
+ };
528
+ }
@@ -0,0 +1,118 @@
1
+ // Copyright (c) Jupyter Development Team.
2
+ // Distributed under the terms of the Modified BSD License.
3
+
4
+ import { CodeConsole, ConsolePanel } from '@jupyterlab/console';
5
+
6
+ import { Cell, CodeCell } from '@jupyterlab/cells';
7
+
8
+ import { IObservableMap, ObservableMap } from '@jupyterlab/observables';
9
+
10
+ import { IDisposable } from '@lumino/disposable';
11
+
12
+ import { Signal } from '@lumino/signaling';
13
+
14
+ import { EditorHandler } from '../handlers/editor';
15
+
16
+ import { IDebugger } from '../tokens';
17
+
18
+ /**
19
+ * A handler for consoles.
20
+ */
21
+ export class ConsoleHandler implements IDisposable {
22
+ /**
23
+ * Instantiate a new ConsoleHandler.
24
+ *
25
+ * @param options The instantiation options for a ConsoleHandler.
26
+ */
27
+ constructor(options: ConsoleHandler.IOptions) {
28
+ this._debuggerService = options.debuggerService;
29
+ this._consolePanel = options.widget;
30
+ this._cellMap = new ObservableMap<EditorHandler>();
31
+
32
+ const codeConsole = this._consolePanel.console;
33
+
34
+ if (codeConsole.promptCell) {
35
+ this._addEditorHandler(codeConsole.promptCell);
36
+ }
37
+ codeConsole.promptCellCreated.connect((_: CodeConsole, cell: CodeCell) => {
38
+ this._addEditorHandler(cell);
39
+ });
40
+
41
+ const addHandlers = (): void => {
42
+ for (const cell of codeConsole.cells) {
43
+ this._addEditorHandler(cell);
44
+ }
45
+ };
46
+ addHandlers();
47
+ this._consolePanel.console.cells.changed.connect(addHandlers);
48
+ }
49
+
50
+ /**
51
+ * Whether the handler is disposed.
52
+ */
53
+ isDisposed: boolean;
54
+
55
+ /**
56
+ * Dispose the handler.
57
+ */
58
+ dispose(): void {
59
+ if (this.isDisposed) {
60
+ return;
61
+ }
62
+ this.isDisposed = true;
63
+ this._cellMap.values().forEach(handler => handler.dispose());
64
+ this._cellMap.dispose();
65
+ Signal.clearData(this);
66
+ }
67
+
68
+ /**
69
+ * Add a new editor handler for the given cell.
70
+ *
71
+ * @param cell The cell to add the handler to.
72
+ */
73
+ private _addEditorHandler(cell: Cell): void {
74
+ const modelId = cell.model.id;
75
+ if (cell.model.type !== 'code' || this._cellMap.has(modelId)) {
76
+ return;
77
+ }
78
+ const codeCell = cell as CodeCell;
79
+ const editorHandler = new EditorHandler({
80
+ debuggerService: this._debuggerService,
81
+ editorReady: async () => {
82
+ await codeCell.ready;
83
+ return codeCell.editor!;
84
+ },
85
+ getEditor: () => codeCell.editor,
86
+ src: cell.model.sharedModel
87
+ });
88
+ codeCell.disposed.connect(() => {
89
+ this._cellMap.delete(modelId);
90
+ editorHandler.dispose();
91
+ });
92
+ this._cellMap.set(modelId, editorHandler);
93
+ }
94
+
95
+ private _consolePanel: ConsolePanel;
96
+ private _debuggerService: IDebugger;
97
+ private _cellMap: IObservableMap<EditorHandler>;
98
+ }
99
+
100
+ /**
101
+ * A namespace for ConsoleHandler `statics`.
102
+ */
103
+ export namespace ConsoleHandler {
104
+ /**
105
+ * Instantiation options for `ConsoleHandler`.
106
+ */
107
+ export interface IOptions {
108
+ /**
109
+ * The debugger service.
110
+ */
111
+ debuggerService: IDebugger;
112
+
113
+ /**
114
+ * The widget to handle.
115
+ */
116
+ widget: ConsolePanel;
117
+ }
118
+ }