|
@@ -7,15 +7,18 @@ import { Widget, Panel, PanelLayout } from '@phosphor/widgets';
|
|
|
import { DebugProtocol } from 'vscode-debugprotocol';
|
|
|
import { Body } from './body';
|
|
|
import { Signal, ISignal } from '@phosphor/signaling';
|
|
|
-import { INotebookTracker } from '@jupyterlab/notebook';
|
|
|
-import { CodeMirrorEditor } from '@jupyterlab/codemirror';
|
|
|
-import { Editor, Doc } from 'codemirror';
|
|
|
-import { CodeCell } from '@jupyterlab/cells';
|
|
|
+import { BreakpointsService } from '../breakpointsService';
|
|
|
|
|
|
export class Breakpoints extends Panel {
|
|
|
constructor(options: Breakpoints.IOptions) {
|
|
|
super();
|
|
|
|
|
|
+ this.service = options.service;
|
|
|
+
|
|
|
+ this.service.selectedBreakpointsChanged.connect((sender, update) => {
|
|
|
+ this.model.breakpoints = update;
|
|
|
+ });
|
|
|
+
|
|
|
this.model = new Breakpoints.IModel([]);
|
|
|
this.addClass('jp-DebuggerBreakpoints');
|
|
|
this.title.label = 'Breakpoints';
|
|
@@ -46,160 +49,17 @@ export class Breakpoints extends Panel {
|
|
|
new ToolbarButton({
|
|
|
iconClassName: 'jp-CloseAllIcon',
|
|
|
onClick: () => {
|
|
|
- this.model.breakpoints = [];
|
|
|
- this.cellsBreakpoints[this.getCell().id] = [];
|
|
|
- this.removeAllGutterBreakpoints(this.getCell());
|
|
|
+ this.service.clearSelectedBreakpoints();
|
|
|
},
|
|
|
tooltip: 'Remove All Breakpoints'
|
|
|
})
|
|
|
);
|
|
|
-
|
|
|
- this.noteTracker = options.noteTracker;
|
|
|
- if (this.noteTracker) {
|
|
|
- this.noteTracker.activeCellChanged.connect(
|
|
|
- this.onActiveCellChanged,
|
|
|
- this
|
|
|
- );
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
private isAllActive = true;
|
|
|
readonly body: Widget;
|
|
|
readonly model: Breakpoints.IModel;
|
|
|
- noteTracker: INotebookTracker;
|
|
|
- previousCell: CodeCell;
|
|
|
- previousLineCount: number;
|
|
|
- cellsBreakpoints: { [id: string]: Breakpoints.IBreakpoint[] } = {};
|
|
|
-
|
|
|
- protected onActiveCellChanged() {
|
|
|
- const activeCell = this.getCell();
|
|
|
- if (this.model && activeCell) {
|
|
|
- if (this.previousCell && !this.previousCell.isDisposed) {
|
|
|
- this.removeListner(this.previousCell);
|
|
|
- }
|
|
|
- this.previousCell = activeCell;
|
|
|
- const id: string = activeCell.model.id;
|
|
|
- if (id && !this.cellsBreakpoints[id]) {
|
|
|
- this.cellsBreakpoints[id] = [];
|
|
|
- }
|
|
|
- this.model.breakpoints = this.cellsBreakpoints[id];
|
|
|
- this.setEditor(activeCell);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- protected getCell(): CodeCell {
|
|
|
- return this.noteTracker.activeCell as CodeCell;
|
|
|
- }
|
|
|
-
|
|
|
- protected removeAllGutterBreakpoints(cell: CodeCell) {
|
|
|
- const editor = cell.editor as CodeMirrorEditor;
|
|
|
- editor.editor.getDoc().eachLine(line => {
|
|
|
- editor.editor.setGutterMarker(line, 'breakpoints', null);
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- removeListner(cell: CodeCell) {
|
|
|
- const editor = cell.editor as CodeMirrorEditor;
|
|
|
- this.cellsBreakpoints[cell.model.id] = this.model.breakpoints;
|
|
|
- this.model.breakpoints = [];
|
|
|
- editor.setOption('lineNumbers', false);
|
|
|
- editor.editor.off('gutterClick', this.onGutterClick);
|
|
|
- editor.editor.off('renderLine', this.onNewRenderLine);
|
|
|
- }
|
|
|
-
|
|
|
- setEditor(cell: CodeCell) {
|
|
|
- if (!cell || !cell.editor) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- const editor = cell.editor as CodeMirrorEditor;
|
|
|
- editor.setOption('lineNumbers', true);
|
|
|
- editor.editor.setOption('gutters', [
|
|
|
- 'CodeMirror-linenumbers',
|
|
|
- 'breakpoints'
|
|
|
- ]);
|
|
|
-
|
|
|
- editor.editor.on('gutterClick', this.onGutterClick);
|
|
|
- editor.editor.on('renderLine', this.onNewRenderLine);
|
|
|
- }
|
|
|
-
|
|
|
- protected onNewRenderLine = (editor: Editor, line: any) => {
|
|
|
- const lineInfo = editor.lineInfo(line);
|
|
|
- if (
|
|
|
- !this.model.breakpoints &&
|
|
|
- this.model.breakpoints.length < 1 &&
|
|
|
- lineInfo.handle &&
|
|
|
- lineInfo.handle.order === false
|
|
|
- ) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- const doc: Doc = editor.getDoc();
|
|
|
- const linesNumber = doc.lineCount();
|
|
|
-
|
|
|
- if (this.previousLineCount !== linesNumber) {
|
|
|
- if (this.previousLineCount > linesNumber) {
|
|
|
- this.model.changeLines(lineInfo.line, -1);
|
|
|
- }
|
|
|
- if (this.previousLineCount < linesNumber) {
|
|
|
- this.model.changeLines(lineInfo.line, +1);
|
|
|
- }
|
|
|
- this.previousLineCount = linesNumber;
|
|
|
- }
|
|
|
- // eage case for backspace line 2
|
|
|
- if (lineInfo.line === 0) {
|
|
|
- const breakpoint: Breakpoints.IBreakpoint = this.model.getBreakpointByLineNumber(
|
|
|
- -1
|
|
|
- );
|
|
|
- if (breakpoint) {
|
|
|
- this.model.removeBreakpoint(breakpoint);
|
|
|
- }
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- private addBreakpoint(line: number) {
|
|
|
- this.model.breakpoint = {
|
|
|
- id: this.model.breakpoints.length + 1,
|
|
|
- active: true,
|
|
|
- verified: true,
|
|
|
- source: {
|
|
|
- // TODO: need get filename
|
|
|
- name: 'untitled.py'
|
|
|
- },
|
|
|
- line: line
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- protected onGutterClick = (editor: Editor, lineNumber: number) => {
|
|
|
- const info = editor.lineInfo(lineNumber);
|
|
|
- if (!info) {
|
|
|
- return;
|
|
|
- }
|
|
|
- const isRemoveGutter = !!info.gutterMarkers;
|
|
|
-
|
|
|
- const breakpoint: Breakpoints.IBreakpoint = this.model.getBreakpointByLineNumber(
|
|
|
- lineNumber
|
|
|
- );
|
|
|
-
|
|
|
- if (!breakpoint && !isRemoveGutter) {
|
|
|
- this.addBreakpoint(lineNumber);
|
|
|
- } else if (isRemoveGutter) {
|
|
|
- this.model.removeBreakpoint(breakpoint);
|
|
|
- }
|
|
|
-
|
|
|
- editor.setGutterMarker(
|
|
|
- lineNumber,
|
|
|
- 'breakpoints',
|
|
|
- isRemoveGutter ? null : this.createMarkerNode()
|
|
|
- );
|
|
|
- };
|
|
|
-
|
|
|
- createMarkerNode() {
|
|
|
- var marker = document.createElement('div');
|
|
|
- marker.className = 'jp-breakpoint-marker';
|
|
|
- marker.innerHTML = '●';
|
|
|
- return marker;
|
|
|
- }
|
|
|
+ service: BreakpointsService;
|
|
|
}
|
|
|
class BreakpointsHeader extends Widget {
|
|
|
constructor(title: string) {
|
|
@@ -246,7 +106,7 @@ export namespace Breakpoints {
|
|
|
|
|
|
set breakpoints(breakpoints: IBreakpoint[]) {
|
|
|
this._state = breakpoints;
|
|
|
- this._breakpointsChanged.emit(this._state);
|
|
|
+ this._breakpointsChanged.emit(breakpoints);
|
|
|
}
|
|
|
|
|
|
set breakpoint(breakpoint: IBreakpoint) {
|
|
@@ -266,18 +126,6 @@ export namespace Breakpoints {
|
|
|
this.breakpoints = breakpoints;
|
|
|
}
|
|
|
|
|
|
- changeLines(lineEnter: number, howMany: number) {
|
|
|
- const breakpoints = this.breakpoints.map(ele => {
|
|
|
- ele.line = lineEnter <= ele.line ? ele.line + howMany : ele.line;
|
|
|
- return ele;
|
|
|
- });
|
|
|
- this.breakpoints = breakpoints;
|
|
|
- }
|
|
|
-
|
|
|
- getBreakpointByLineNumber(lineNumber: number) {
|
|
|
- return this.breakpoints.find(ele => ele.line === lineNumber);
|
|
|
- }
|
|
|
-
|
|
|
private _state: IBreakpoint[];
|
|
|
private _breakpointsChanged = new Signal<this, IBreakpoint[]>(this);
|
|
|
private _breakpointChanged = new Signal<this, IBreakpoint>(this);
|
|
@@ -287,6 +135,6 @@ export namespace Breakpoints {
|
|
|
* Instantiation options for `Breakpoints`;
|
|
|
*/
|
|
|
export interface IOptions extends Panel.IOptions {
|
|
|
- noteTracker?: INotebookTracker;
|
|
|
+ service?: BreakpointsService;
|
|
|
}
|
|
|
}
|