@jupyterlab/debugger 4.0.0-alpha.8 → 4.0.0-beta.0
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.
- package/lib/debugger.d.ts +3 -1
- package/lib/debugger.js +5 -3
- package/lib/debugger.js.map +1 -1
- package/lib/dialogs/evaluate.d.ts +5 -0
- package/lib/dialogs/evaluate.js +16 -6
- package/lib/dialogs/evaluate.js.map +1 -1
- package/lib/factory.d.ts +1 -1
- package/lib/factory.js +15 -9
- package/lib/factory.js.map +1 -1
- package/lib/handler.js +15 -7
- package/lib/handler.js.map +1 -1
- package/lib/handlers/console.js +9 -3
- package/lib/handlers/console.js.map +1 -1
- package/lib/handlers/editor.d.ts +26 -12
- package/lib/handlers/editor.js +166 -89
- package/lib/handlers/editor.js.map +1 -1
- package/lib/handlers/file.js +6 -2
- package/lib/handlers/file.js.map +1 -1
- package/lib/handlers/notebook.d.ts +0 -7
- package/lib/handlers/notebook.js +11 -17
- package/lib/handlers/notebook.js.map +1 -1
- package/lib/icons.d.ts +2 -1
- package/lib/icons.js +6 -1
- package/lib/icons.js.map +1 -1
- package/lib/model.js +1 -0
- package/lib/model.js.map +1 -1
- package/lib/panels/breakpoints/index.d.ts +2 -2
- package/lib/panels/breakpoints/index.js +9 -7
- package/lib/panels/breakpoints/index.js.map +1 -1
- package/lib/panels/breakpoints/pauseonexceptions.d.ts +53 -0
- package/lib/panels/breakpoints/pauseonexceptions.js +98 -0
- package/lib/panels/breakpoints/pauseonexceptions.js.map +1 -0
- package/lib/panels/callstack/index.d.ts +1 -1
- package/lib/panels/kernelSources/body.d.ts +5 -7
- package/lib/panels/kernelSources/body.js +37 -47
- package/lib/panels/kernelSources/body.js.map +1 -1
- package/lib/panels/kernelSources/filter.d.ts +1 -2
- package/lib/panels/kernelSources/filter.js +2 -2
- package/lib/panels/kernelSources/filter.js.map +1 -1
- package/lib/panels/kernelSources/index.js +1 -1
- package/lib/panels/kernelSources/index.js.map +1 -1
- package/lib/panels/kernelSources/model.d.ts +10 -1
- package/lib/panels/kernelSources/model.js +19 -1
- package/lib/panels/kernelSources/model.js.map +1 -1
- package/lib/panels/sources/body.js +5 -3
- package/lib/panels/sources/body.js.map +1 -1
- package/lib/panels/variables/grid.d.ts +10 -0
- package/lib/panels/variables/grid.js +28 -351
- package/lib/panels/variables/grid.js.map +1 -1
- package/lib/panels/variables/gridpanel.d.ts +140 -0
- package/lib/panels/variables/gridpanel.js +363 -0
- package/lib/panels/variables/gridpanel.js.map +1 -0
- package/lib/panels/variables/mimerenderer.js +9 -1
- package/lib/panels/variables/mimerenderer.js.map +1 -1
- package/lib/panels/variables/scope.js +4 -0
- package/lib/panels/variables/scope.js.map +1 -1
- package/lib/panels/variables/tree.d.ts +1 -0
- package/lib/panels/variables/tree.js +136 -47
- package/lib/panels/variables/tree.js.map +1 -1
- package/lib/service.d.ts +20 -6
- package/lib/service.js +84 -59
- package/lib/service.js.map +1 -1
- package/lib/session.d.ts +20 -6
- package/lib/session.js +59 -11
- package/lib/session.js.map +1 -1
- package/lib/sidebar.js +1 -1
- package/lib/sources.d.ts +2 -2
- package/lib/sources.js +32 -17
- package/lib/sources.js.map +1 -1
- package/lib/tokens.d.ts +57 -13
- package/lib/tokens.js.map +1 -1
- package/package.json +39 -47
- package/src/config.ts +78 -0
- package/src/debugger.ts +154 -0
- package/src/dialogs/evaluate.ts +144 -0
- package/src/factory.ts +72 -0
- package/src/handler.ts +528 -0
- package/src/handlers/console.ts +118 -0
- package/src/handlers/editor.ts +469 -0
- package/src/handlers/file.ts +86 -0
- package/src/handlers/notebook.ts +128 -0
- package/src/hash.ts +69 -0
- package/src/icons.ts +64 -0
- package/src/index.ts +16 -0
- package/src/model.ts +155 -0
- package/src/panels/breakpoints/body.tsx +145 -0
- package/src/panels/breakpoints/index.ts +116 -0
- package/src/panels/breakpoints/model.ts +74 -0
- package/src/panels/breakpoints/pauseonexceptions.tsx +141 -0
- package/src/panels/callstack/body.tsx +96 -0
- package/src/panels/callstack/index.ts +152 -0
- package/src/panels/callstack/model.ts +86 -0
- package/src/panels/kernelSources/body.tsx +139 -0
- package/src/panels/kernelSources/filter.tsx +44 -0
- package/src/panels/kernelSources/index.tsx +106 -0
- package/src/panels/kernelSources/model.ts +160 -0
- package/src/panels/sources/body.ts +161 -0
- package/src/panels/sources/index.tsx +85 -0
- package/src/panels/sources/model.ts +94 -0
- package/src/panels/sources/sourcepath.tsx +28 -0
- package/src/panels/variables/grid.ts +144 -0
- package/src/panels/variables/gridpanel.ts +455 -0
- package/src/panels/variables/index.ts +199 -0
- package/src/panels/variables/mimerenderer.ts +125 -0
- package/src/panels/variables/model.ts +61 -0
- package/src/panels/variables/scope.tsx +132 -0
- package/src/panels/variables/tree.tsx +521 -0
- package/src/service.ts +1009 -0
- package/src/session.ts +342 -0
- package/src/sidebar.ts +194 -0
- package/src/sources.ts +327 -0
- package/src/svg.d.ts +9 -0
- package/src/tokens.ts +1071 -0
- package/style/breakpoints.css +21 -12
- package/style/icons/exceptions.svg +10 -0
- package/style/index.css +1 -1
- package/style/index.js +1 -1
- package/style/kernelSources.css +3 -0
- package/style/variables.css +68 -21
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
// Copyright (c) Jupyter Development Team.
|
|
2
|
+
// Distributed under the terms of the Modified BSD License.
|
|
3
|
+
|
|
4
|
+
import { CodeEditor } from '@jupyterlab/codeeditor';
|
|
5
|
+
|
|
6
|
+
import { CodeMirrorEditor } from '@jupyterlab/codemirror';
|
|
7
|
+
|
|
8
|
+
import { ActivityMonitor } from '@jupyterlab/coreutils';
|
|
9
|
+
|
|
10
|
+
import { IDisposable } from '@lumino/disposable';
|
|
11
|
+
|
|
12
|
+
import { Signal } from '@lumino/signaling';
|
|
13
|
+
|
|
14
|
+
import { ISharedText, SourceChange } from '@jupyter/ydoc';
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
Compartment,
|
|
18
|
+
Prec,
|
|
19
|
+
RangeSet,
|
|
20
|
+
StateEffect,
|
|
21
|
+
StateEffectType,
|
|
22
|
+
StateField
|
|
23
|
+
} from '@codemirror/state';
|
|
24
|
+
|
|
25
|
+
import {
|
|
26
|
+
Decoration,
|
|
27
|
+
DecorationSet,
|
|
28
|
+
EditorView,
|
|
29
|
+
gutter,
|
|
30
|
+
GutterMarker
|
|
31
|
+
} from '@codemirror/view';
|
|
32
|
+
|
|
33
|
+
import { IDebugger } from '../tokens';
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The class name added to the current line.
|
|
37
|
+
*/
|
|
38
|
+
const LINE_HIGHLIGHT_CLASS = 'jp-DebuggerEditor-highlight';
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The timeout for listening to editor content changes.
|
|
42
|
+
*/
|
|
43
|
+
const EDITOR_CHANGED_TIMEOUT = 1000;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* A handler for a CodeEditor.IEditor.
|
|
47
|
+
*/
|
|
48
|
+
export class EditorHandler implements IDisposable {
|
|
49
|
+
/**
|
|
50
|
+
* Instantiate a new EditorHandler.
|
|
51
|
+
*
|
|
52
|
+
* @param options The instantiation options for a EditorHandler.
|
|
53
|
+
*/
|
|
54
|
+
constructor(options: EditorHandler.IOptions) {
|
|
55
|
+
this._src = options.src;
|
|
56
|
+
this._id = options.debuggerService.session?.connection?.id ?? '';
|
|
57
|
+
this._path = options.path ?? '';
|
|
58
|
+
this._debuggerService = options.debuggerService;
|
|
59
|
+
this._editor = options.getEditor;
|
|
60
|
+
|
|
61
|
+
this._editorMonitor = new ActivityMonitor({
|
|
62
|
+
signal: this._src.changed,
|
|
63
|
+
timeout: EDITOR_CHANGED_TIMEOUT
|
|
64
|
+
});
|
|
65
|
+
this._editorMonitor.activityStopped.connect(() => {
|
|
66
|
+
this._sendEditorBreakpoints();
|
|
67
|
+
}, this);
|
|
68
|
+
|
|
69
|
+
this._debuggerService.model.breakpoints.changed.connect(async () => {
|
|
70
|
+
const editor = this.editor;
|
|
71
|
+
if (!editor || editor.isDisposed) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
this._addBreakpointsToEditor();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
this._debuggerService.model.breakpoints.restored.connect(async () => {
|
|
78
|
+
const editor = this.editor;
|
|
79
|
+
if (!editor || editor.isDisposed) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
this._addBreakpointsToEditor();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
this._debuggerService.model.callstack.currentFrameChanged.connect(() => {
|
|
86
|
+
const editor = this.editor;
|
|
87
|
+
if (editor) {
|
|
88
|
+
EditorHandler.clearHighlight(editor);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
this._breakpointEffect = StateEffect.define<{ pos: number[] }>({
|
|
93
|
+
map: (value, mapping) => ({ pos: value.pos.map(v => mapping.mapPos(v)) })
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
this._breakpointState = StateField.define<RangeSet<GutterMarker>>({
|
|
97
|
+
create: () => {
|
|
98
|
+
return RangeSet.empty;
|
|
99
|
+
},
|
|
100
|
+
update: (breakpoints, transaction) => {
|
|
101
|
+
breakpoints = breakpoints.map(transaction.changes);
|
|
102
|
+
for (let ef of transaction.effects) {
|
|
103
|
+
if (ef.is(this._breakpointEffect)) {
|
|
104
|
+
let e = ef as StateEffect<{ pos: number[] }>;
|
|
105
|
+
if (e.value.pos.length) {
|
|
106
|
+
breakpoints = breakpoints.update({
|
|
107
|
+
add: e.value.pos.map(v => Private.breakpointMarker.range(v)),
|
|
108
|
+
sort: true
|
|
109
|
+
});
|
|
110
|
+
} else {
|
|
111
|
+
breakpoints = RangeSet.empty;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return breakpoints;
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
this._gutter = new Compartment();
|
|
120
|
+
|
|
121
|
+
this._highlightDeco = Decoration.line({ class: LINE_HIGHLIGHT_CLASS });
|
|
122
|
+
|
|
123
|
+
this._highlightState = StateField.define<DecorationSet>({
|
|
124
|
+
create: () => {
|
|
125
|
+
return Decoration.none;
|
|
126
|
+
},
|
|
127
|
+
update: (highlights, transaction) => {
|
|
128
|
+
highlights = highlights.map(transaction.changes);
|
|
129
|
+
for (let ef of transaction.effects) {
|
|
130
|
+
if (ef.is(EditorHandler._highlightEffect)) {
|
|
131
|
+
let e = ef as StateEffect<{ pos: number[] }>;
|
|
132
|
+
if (e.value.pos.length) {
|
|
133
|
+
highlights = highlights.update({
|
|
134
|
+
add: e.value.pos.map(v => this._highlightDeco.range(v))
|
|
135
|
+
});
|
|
136
|
+
} else {
|
|
137
|
+
highlights = Decoration.none;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return highlights;
|
|
142
|
+
},
|
|
143
|
+
provide: f => EditorView.decorations.from(f)
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
void options.editorReady().then(() => {
|
|
147
|
+
this._setupEditor();
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* The editor
|
|
153
|
+
*/
|
|
154
|
+
get editor(): CodeEditor.IEditor | null {
|
|
155
|
+
return this._editor();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Whether the handler is disposed.
|
|
160
|
+
*/
|
|
161
|
+
isDisposed: boolean;
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Dispose the handler.
|
|
165
|
+
*/
|
|
166
|
+
dispose(): void {
|
|
167
|
+
if (this.isDisposed) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
this._editorMonitor.dispose();
|
|
171
|
+
this._clearEditor();
|
|
172
|
+
this.isDisposed = true;
|
|
173
|
+
Signal.clearData(this);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Refresh the breakpoints display
|
|
178
|
+
*/
|
|
179
|
+
refreshBreakpoints(): void {
|
|
180
|
+
this._addBreakpointsToEditor();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Setup the editor.
|
|
185
|
+
*/
|
|
186
|
+
private _setupEditor(): void {
|
|
187
|
+
const editor = this.editor;
|
|
188
|
+
if (!editor || editor.isDisposed) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
editor.setOption('lineNumbers', true);
|
|
193
|
+
const breakpointGutter = [
|
|
194
|
+
this._breakpointState,
|
|
195
|
+
this._highlightState,
|
|
196
|
+
Prec.highest(
|
|
197
|
+
gutter({
|
|
198
|
+
class: 'cm-breakpoint-gutter',
|
|
199
|
+
renderEmptyElements: true,
|
|
200
|
+
markers: v => v.state.field(this._breakpointState),
|
|
201
|
+
initialSpacer: () => Private.breakpointMarker,
|
|
202
|
+
domEventHandlers: {
|
|
203
|
+
mousedown: (view, line): boolean => {
|
|
204
|
+
this._onGutterClick(view, line.from);
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
})
|
|
209
|
+
)
|
|
210
|
+
];
|
|
211
|
+
editor.injectExtension(this._gutter.of(breakpointGutter));
|
|
212
|
+
|
|
213
|
+
this._addBreakpointsToEditor();
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Clear the editor by removing visual elements and handlers.
|
|
218
|
+
*/
|
|
219
|
+
private _clearEditor(): void {
|
|
220
|
+
const editor = this.editor as CodeMirrorEditor | null;
|
|
221
|
+
if (!editor || editor.isDisposed) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
EditorHandler.clearHighlight(editor);
|
|
226
|
+
this._clearGutter(editor);
|
|
227
|
+
editor.setOption('lineNumbers', false);
|
|
228
|
+
editor.editor.dispatch({
|
|
229
|
+
effects: this._gutter.reconfigure([])
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Send the breakpoints from the editor UI via the debug service.
|
|
235
|
+
*/
|
|
236
|
+
private _sendEditorBreakpoints(): void {
|
|
237
|
+
if (this.editor?.isDisposed) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const breakpoints = this._getBreakpointsFromEditor().map(lineNumber => {
|
|
242
|
+
return Private.createBreakpoint(
|
|
243
|
+
this._debuggerService.session?.connection?.name || '',
|
|
244
|
+
lineNumber
|
|
245
|
+
);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
void this._debuggerService.updateBreakpoints(
|
|
249
|
+
this._src.getSource(),
|
|
250
|
+
breakpoints,
|
|
251
|
+
this._path
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Handle a click on the gutter.
|
|
257
|
+
*
|
|
258
|
+
* @param editor The editor from where the click originated.
|
|
259
|
+
* @param position The position corresponding to the click event.
|
|
260
|
+
*/
|
|
261
|
+
private _onGutterClick(editor: EditorView, position: number): void {
|
|
262
|
+
if (this._id !== this._debuggerService.session?.connection?.id) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const lineNumber = editor.state.doc.lineAt(position).number;
|
|
267
|
+
let stateBreakpoints = editor.state.field(this._breakpointState);
|
|
268
|
+
let hasBreakpoint = false;
|
|
269
|
+
stateBreakpoints.between(position, position, () => {
|
|
270
|
+
hasBreakpoint = true;
|
|
271
|
+
});
|
|
272
|
+
let breakpoints: IDebugger.IBreakpoint[] = this._getBreakpoints();
|
|
273
|
+
if (hasBreakpoint) {
|
|
274
|
+
breakpoints = breakpoints.filter(ele => ele.line !== lineNumber);
|
|
275
|
+
} else {
|
|
276
|
+
breakpoints.push(
|
|
277
|
+
Private.createBreakpoint(
|
|
278
|
+
this._path ?? this._debuggerService.session.connection.name,
|
|
279
|
+
lineNumber
|
|
280
|
+
)
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
breakpoints.sort((a, b) => {
|
|
285
|
+
return a.line! - b.line!;
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
void this._debuggerService.updateBreakpoints(
|
|
289
|
+
this._src.getSource(),
|
|
290
|
+
breakpoints,
|
|
291
|
+
this._path
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Add the breakpoints to the editor.
|
|
297
|
+
*/
|
|
298
|
+
private _addBreakpointsToEditor(): void {
|
|
299
|
+
if (this._id !== this._debuggerService.session?.connection?.id) {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const editor = this.editor as CodeMirrorEditor;
|
|
304
|
+
const breakpoints = this._getBreakpoints();
|
|
305
|
+
|
|
306
|
+
this._clearGutter(editor);
|
|
307
|
+
const breakpointPos = breakpoints.map(b => {
|
|
308
|
+
return editor.state.doc.line(b.line!).from;
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
editor.editor.dispatch({
|
|
312
|
+
effects: this._breakpointEffect.of({ pos: breakpointPos })
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Retrieve the breakpoints from the editor.
|
|
318
|
+
*/
|
|
319
|
+
private _getBreakpointsFromEditor(): number[] {
|
|
320
|
+
const editor = this.editor as CodeMirrorEditor;
|
|
321
|
+
const breakpoints = editor.editor.state.field(this._breakpointState);
|
|
322
|
+
let lines: number[] = [];
|
|
323
|
+
breakpoints.between(0, editor.doc.length, (from: number) => {
|
|
324
|
+
lines.push(editor.doc.lineAt(from).number);
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
return lines;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
private _clearGutter(editor: CodeEditor.IEditor): void {
|
|
331
|
+
if (!editor) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const view = (editor as CodeMirrorEditor).editor;
|
|
336
|
+
view.dispatch({
|
|
337
|
+
effects: this._breakpointEffect.of({ pos: [] })
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Get the breakpoints for the editor using its content (code),
|
|
343
|
+
* or its path (if it exists).
|
|
344
|
+
*/
|
|
345
|
+
private _getBreakpoints(): IDebugger.IBreakpoint[] {
|
|
346
|
+
const code = this._src.getSource();
|
|
347
|
+
return this._debuggerService.model.breakpoints.getBreakpoints(
|
|
348
|
+
this._path || this._debuggerService.getCodeId(code)
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
private _id: string;
|
|
353
|
+
private _debuggerService: IDebugger;
|
|
354
|
+
private _editor: () => CodeEditor.IEditor | null;
|
|
355
|
+
private _breakpointEffect: StateEffectType<{ pos: number[] }>;
|
|
356
|
+
private _breakpointState: StateField<RangeSet<GutterMarker>>;
|
|
357
|
+
private _gutter: Compartment;
|
|
358
|
+
private _highlightDeco: Decoration;
|
|
359
|
+
private _highlightState: StateField<DecorationSet>;
|
|
360
|
+
private _editorMonitor: ActivityMonitor<ISharedText, SourceChange>;
|
|
361
|
+
private _path: string;
|
|
362
|
+
private _src: ISharedText;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* A namespace for EditorHandler `statics`.
|
|
367
|
+
*/
|
|
368
|
+
export namespace EditorHandler {
|
|
369
|
+
/**
|
|
370
|
+
* Instantiation options for `EditorHandler`.
|
|
371
|
+
*/
|
|
372
|
+
export interface IOptions {
|
|
373
|
+
/**
|
|
374
|
+
* The debugger service.
|
|
375
|
+
*/
|
|
376
|
+
debuggerService: IDebugger;
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Promise resolving when the editor is ready.
|
|
380
|
+
*/
|
|
381
|
+
editorReady(): Promise<CodeEditor.IEditor>;
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Get the code editor to handle.
|
|
385
|
+
*/
|
|
386
|
+
getEditor(): CodeEditor.IEditor | null;
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* An optional path to a source file.
|
|
390
|
+
*/
|
|
391
|
+
path?: string;
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* The code source to debug
|
|
395
|
+
*/
|
|
396
|
+
src: ISharedText;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
export const _highlightEffect = StateEffect.define<{ pos: number[] }>({
|
|
400
|
+
map: (value, mapping) => ({ pos: value.pos.map(v => mapping.mapPos(v)) })
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Highlight the current line of the frame in the given editor.
|
|
405
|
+
*
|
|
406
|
+
* @param editor The editor to highlight.
|
|
407
|
+
* @param line The line number.
|
|
408
|
+
*/
|
|
409
|
+
export function showCurrentLine(
|
|
410
|
+
editor: CodeEditor.IEditor,
|
|
411
|
+
line: number
|
|
412
|
+
): void {
|
|
413
|
+
clearHighlight(editor);
|
|
414
|
+
const cmEditor = editor as CodeMirrorEditor;
|
|
415
|
+
const linePos = cmEditor.doc.line(line).from;
|
|
416
|
+
cmEditor.editor.dispatch({
|
|
417
|
+
effects: _highlightEffect.of({ pos: [linePos] })
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Remove all line highlighting indicators for the given editor.
|
|
423
|
+
*
|
|
424
|
+
* @param editor The editor to cleanup.
|
|
425
|
+
*/
|
|
426
|
+
export function clearHighlight(editor: CodeEditor.IEditor): void {
|
|
427
|
+
if (!editor || editor.isDisposed) {
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
const cmEditor = editor as CodeMirrorEditor;
|
|
431
|
+
cmEditor.editor.dispatch({
|
|
432
|
+
effects: _highlightEffect.of({ pos: [] })
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* A namespace for module private data.
|
|
439
|
+
*/
|
|
440
|
+
namespace Private {
|
|
441
|
+
/**
|
|
442
|
+
* Create a marker DOM element for a breakpoint.
|
|
443
|
+
*/
|
|
444
|
+
export const breakpointMarker = new (class extends GutterMarker {
|
|
445
|
+
toDOM() {
|
|
446
|
+
const marker = document.createTextNode('●');
|
|
447
|
+
return marker;
|
|
448
|
+
}
|
|
449
|
+
})();
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Create a new breakpoint.
|
|
453
|
+
*
|
|
454
|
+
* @param session The name of the session.
|
|
455
|
+
* @param line The line number of the breakpoint.
|
|
456
|
+
*/
|
|
457
|
+
export function createBreakpoint(
|
|
458
|
+
session: string,
|
|
459
|
+
line: number
|
|
460
|
+
): IDebugger.IBreakpoint {
|
|
461
|
+
return {
|
|
462
|
+
line,
|
|
463
|
+
verified: true,
|
|
464
|
+
source: {
|
|
465
|
+
name: session
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// Copyright (c) Jupyter Development Team.
|
|
2
|
+
// Distributed under the terms of the Modified BSD License.
|
|
3
|
+
|
|
4
|
+
import { DocumentWidget } from '@jupyterlab/docregistry';
|
|
5
|
+
|
|
6
|
+
import { FileEditor } from '@jupyterlab/fileeditor';
|
|
7
|
+
|
|
8
|
+
import { IDisposable } from '@lumino/disposable';
|
|
9
|
+
|
|
10
|
+
import { Signal } from '@lumino/signaling';
|
|
11
|
+
|
|
12
|
+
import { EditorHandler } from '../handlers/editor';
|
|
13
|
+
|
|
14
|
+
import { IDebugger } from '../tokens';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* A handler for files.
|
|
18
|
+
*/
|
|
19
|
+
export class FileHandler implements IDisposable {
|
|
20
|
+
/**
|
|
21
|
+
* Instantiate a new FileHandler.
|
|
22
|
+
*
|
|
23
|
+
* @param options The instantiation options for a FileHandler.
|
|
24
|
+
*/
|
|
25
|
+
constructor(options: FileHandler.IOptions) {
|
|
26
|
+
this._debuggerService = options.debuggerService;
|
|
27
|
+
this._fileEditor = options.widget.content;
|
|
28
|
+
|
|
29
|
+
this._hasLineNumber =
|
|
30
|
+
(this._fileEditor.editor.getOption('lineNumbers') as
|
|
31
|
+
| boolean
|
|
32
|
+
| undefined) ?? false;
|
|
33
|
+
this._editorHandler = new EditorHandler({
|
|
34
|
+
debuggerService: this._debuggerService,
|
|
35
|
+
editorReady: () => Promise.resolve(this._fileEditor.editor),
|
|
36
|
+
getEditor: () => this._fileEditor.editor,
|
|
37
|
+
src: this._fileEditor.model.sharedModel
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Whether the handler is disposed.
|
|
43
|
+
*/
|
|
44
|
+
isDisposed: boolean;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Dispose the handler.
|
|
48
|
+
*/
|
|
49
|
+
dispose(): void {
|
|
50
|
+
if (this.isDisposed) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
this.isDisposed = true;
|
|
54
|
+
this._editorHandler?.dispose();
|
|
55
|
+
// Restore editor options
|
|
56
|
+
this._editorHandler?.editor!.setOptions({
|
|
57
|
+
lineNumbers: this._hasLineNumber
|
|
58
|
+
});
|
|
59
|
+
Signal.clearData(this);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private _fileEditor: FileEditor;
|
|
63
|
+
private _debuggerService: IDebugger;
|
|
64
|
+
private _editorHandler: EditorHandler;
|
|
65
|
+
private _hasLineNumber: boolean;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* A namespace for FileHandler `statics`.
|
|
70
|
+
*/
|
|
71
|
+
export namespace FileHandler {
|
|
72
|
+
/**
|
|
73
|
+
* Instantiation options for `FileHandler`.
|
|
74
|
+
*/
|
|
75
|
+
export interface IOptions {
|
|
76
|
+
/**
|
|
77
|
+
* The debugger service.
|
|
78
|
+
*/
|
|
79
|
+
debuggerService: IDebugger;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* The widget to handle.
|
|
83
|
+
*/
|
|
84
|
+
widget: DocumentWidget<FileEditor>;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// Copyright (c) Jupyter Development Team.
|
|
2
|
+
// Distributed under the terms of the Modified BSD License.
|
|
3
|
+
|
|
4
|
+
import { Cell, CodeCell, ICellModel } from '@jupyterlab/cells';
|
|
5
|
+
import { NotebookPanel } from '@jupyterlab/notebook';
|
|
6
|
+
import {
|
|
7
|
+
IObservableList,
|
|
8
|
+
IObservableMap,
|
|
9
|
+
ObservableMap
|
|
10
|
+
} from '@jupyterlab/observables';
|
|
11
|
+
import { IDisposable } from '@lumino/disposable';
|
|
12
|
+
import { Signal } from '@lumino/signaling';
|
|
13
|
+
import { IDebugger } from '../tokens';
|
|
14
|
+
import { EditorHandler } from './editor';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* A handler for notebooks.
|
|
18
|
+
*/
|
|
19
|
+
export class NotebookHandler implements IDisposable {
|
|
20
|
+
/**
|
|
21
|
+
* Instantiate a new NotebookHandler.
|
|
22
|
+
*
|
|
23
|
+
* @param options The instantiation options for a NotebookHandler.
|
|
24
|
+
*/
|
|
25
|
+
constructor(options: NotebookHandler.IOptions) {
|
|
26
|
+
this._debuggerService = options.debuggerService;
|
|
27
|
+
this._notebookPanel = options.widget;
|
|
28
|
+
this._cellMap = new ObservableMap<EditorHandler>();
|
|
29
|
+
|
|
30
|
+
const notebook = this._notebookPanel.content;
|
|
31
|
+
notebook.model!.cells.changed.connect(this._onCellsChanged, this);
|
|
32
|
+
|
|
33
|
+
this._onCellsChanged();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Whether the handler is disposed.
|
|
38
|
+
*/
|
|
39
|
+
isDisposed: boolean;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Dispose the handler.
|
|
43
|
+
*/
|
|
44
|
+
dispose(): void {
|
|
45
|
+
if (this.isDisposed) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
this.isDisposed = true;
|
|
49
|
+
this._cellMap.values().forEach(handler => {
|
|
50
|
+
handler.dispose();
|
|
51
|
+
// Ensure to restore notebook editor settings
|
|
52
|
+
handler.editor?.setOptions({
|
|
53
|
+
...this._notebookPanel.content.editorConfig.code
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
this._cellMap.dispose();
|
|
57
|
+
Signal.clearData(this);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Handle a notebook cells changed event.
|
|
62
|
+
*/
|
|
63
|
+
private _onCellsChanged(
|
|
64
|
+
cells?: any,
|
|
65
|
+
changes?: IObservableList.IChangedArgs<ICellModel>
|
|
66
|
+
): void {
|
|
67
|
+
this._notebookPanel.content.widgets.forEach(cell =>
|
|
68
|
+
this._addEditorHandler(cell)
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
if (changes?.type === 'move') {
|
|
72
|
+
for (const cell of changes.newValues) {
|
|
73
|
+
this._cellMap.get(cell.id)?.refreshBreakpoints();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Add a new editor handler for the given cell.
|
|
80
|
+
*
|
|
81
|
+
* @param cell The cell to add the handler to.
|
|
82
|
+
*/
|
|
83
|
+
private _addEditorHandler(cell: Cell): void {
|
|
84
|
+
const modelId = cell.model.id;
|
|
85
|
+
if (cell.model.type !== 'code' || this._cellMap.has(modelId)) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const codeCell = cell as CodeCell;
|
|
89
|
+
const editorHandler = new EditorHandler({
|
|
90
|
+
debuggerService: this._debuggerService,
|
|
91
|
+
editorReady: async () => {
|
|
92
|
+
await codeCell.ready;
|
|
93
|
+
return codeCell.editor!;
|
|
94
|
+
},
|
|
95
|
+
getEditor: () => codeCell.editor,
|
|
96
|
+
src: cell.model.sharedModel
|
|
97
|
+
});
|
|
98
|
+
codeCell.disposed.connect(() => {
|
|
99
|
+
this._cellMap.delete(modelId);
|
|
100
|
+
editorHandler.dispose();
|
|
101
|
+
});
|
|
102
|
+
this._cellMap.set(cell.model.id, editorHandler);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private _debuggerService: IDebugger;
|
|
106
|
+
private _notebookPanel: NotebookPanel;
|
|
107
|
+
private _cellMap: IObservableMap<EditorHandler>;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* A namespace for NotebookHandler statics.
|
|
112
|
+
*/
|
|
113
|
+
export namespace NotebookHandler {
|
|
114
|
+
/**
|
|
115
|
+
* Instantiation options for `NotebookHandler`.
|
|
116
|
+
*/
|
|
117
|
+
export interface IOptions {
|
|
118
|
+
/**
|
|
119
|
+
* The debugger service.
|
|
120
|
+
*/
|
|
121
|
+
debuggerService: IDebugger;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* The widget to handle.
|
|
125
|
+
*/
|
|
126
|
+
widget: NotebookPanel;
|
|
127
|
+
}
|
|
128
|
+
}
|