Skip to content
This repository has been archived by the owner on Jan 26, 2022. It is now read-only.

Connect Breakpoints widget with NoteBook #36

Merged
merged 46 commits into from
Oct 3, 2019
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
c5b8d24
some changes
KsavinN Aug 29, 2019
833b2cc
add setting breakpoint in UI
KsavinN Aug 30, 2019
e60f900
add notebooktracker to breakpoint wideget
KsavinN Sep 2, 2019
e6bd0dc
Merge branch 'notebook_lines' into debugger-ui
KsavinN Sep 2, 2019
b3e1fa7
debug for test
KsavinN Sep 2, 2019
5ad3971
add method for update breakpoints after changedLines in Notebook
KsavinN Sep 3, 2019
484108a
develope toogle remove all breakpoints
KsavinN Sep 3, 2019
ec77927
Merge branch 'notebook_lines' into debugger-ui
KsavinN Sep 3, 2019
2b0ce1d
changes
KsavinN Sep 6, 2019
c37f31c
refactor , suggest by Jeremy
KsavinN Sep 9, 2019
01aa541
rename INoteTracker variable
KsavinN Sep 9, 2019
8752e6f
Merge pull request #8 from jupyterlab/master
KsavinN Sep 9, 2019
061feff
add DebugerNotebookTracker
KsavinN Sep 9, 2019
2d676fa
Merge branch 'master' into session
KsavinN Sep 9, 2019
7dd3752
add breakpointservice
KsavinN Sep 11, 2019
47d0bb3
add service instance
KsavinN Sep 11, 2019
d303fcd
remove breakpoints
KsavinN Sep 12, 2019
7da863f
change breakpoints UI during new lines
KsavinN Sep 12, 2019
b7551a1
Merge branch 'session' into debugger-ui
KsavinN Sep 12, 2019
743347f
debug forr tests
KsavinN Sep 12, 2019
25b1dc8
new method for redner line
KsavinN Sep 16, 2019
a3995cb
add cellManager
KsavinN Sep 16, 2019
681a7d8
Merge branch 'session' into debugger-ui
KsavinN Sep 17, 2019
7f50def
add and debeug consoletracker plugin
KsavinN Sep 18, 2019
951a239
debug consoleTracker
KsavinN Sep 18, 2019
c24b512
Merge branch 'session' into debugger-ui
KsavinN Sep 18, 2019
fe547a4
check type of kernel and set breakpoints
KsavinN Sep 19, 2019
a0bdb64
Merge branch 'session' into debugger-ui
KsavinN Sep 19, 2019
fdd97c2
Rename/reorganize some paths.
afshin Sep 20, 2019
6fcd20f
BROKEN - just for comments
afshin Sep 25, 2019
6e63811
Merge pull request #9 from afshin/debugger-ui
KsavinN Sep 25, 2019
a053c95
refactoring, still work in progress
KsavinN Sep 27, 2019
c8c3a85
Export debugger sidebar.
afshin Sep 27, 2019
a2d10a6
next refactor
KsavinN Sep 27, 2019
e6c6fa9
Merge branch 'debugger-ui' of https://github.com/afshin/debugger into…
KsavinN Sep 27, 2019
933fade
delete breakpointService , set sidebar in to model of Debuger
KsavinN Sep 27, 2019
0297d8d
add Tracker for handlers between console/notebook
KsavinN Sep 30, 2019
2915521
fix line numbers for breakpoints
KsavinN Oct 1, 2019
85d59d9
fix line numbers for breakpoints
KsavinN Oct 1, 2019
f0f1186
Merge branch 'debugger-ui' of github.com:KsavinN/debugger into debugg…
KsavinN Oct 1, 2019
28bdc70
fix edge cases
KsavinN Oct 1, 2019
9355956
Add sessionChanged signal.
afshin Oct 1, 2019
1baa7f4
set session only in debugger model
KsavinN Oct 1, 2019
d7071cc
set session only in debugger model
KsavinN Oct 1, 2019
79cbf93
Merge branch 'debugger-ui' of github.com:KsavinN/debugger into debugg…
KsavinN Oct 1, 2019
6cd90a5
add debugger widget to main
KsavinN Oct 2, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"@phosphor/coreutils": "^1.3.1",
"@phosphor/disposable": "^1.2.0",
"@phosphor/widgets": "^1.8.0",
"@types/codemirror": "0.0.76",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should go to devDependencies

"vscode-debugprotocol": "1.35.0"
},
"devDependencies": {
Expand Down
4 changes: 2 additions & 2 deletions src/breakpoints/body.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ const BreakpointsComponent = ({ model }: { model: Breakpoints.IModel }) => {

return (
<div>
{breakpoints.map((breakpoint: any) => (
{breakpoints.map((breakpoint: Breakpoints.IBreakpoint) => (
<BreakpointComponent
key={breakpoint.id}
key={breakpoint.line}
breakpoint={breakpoint}
breakpointChanged={model.breakpointChanged}
/>
Expand Down
201 changes: 175 additions & 26 deletions src/breakpoints/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,16 @@ 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';

export class Breakpoints extends Panel {
constructor(options: Breakpoints.IOptions = {}) {
constructor(options: Breakpoints.IOptions) {
super();

this.model = new Breakpoints.IModel(MOCK_BREAKPOINTS);
this.model = new Breakpoints.IModel([]);
this.addClass('jp-DebuggerBreakpoints');
this.title.label = 'Breakpoints';

Expand Down Expand Up @@ -43,17 +47,160 @@ export class Breakpoints extends Panel {
iconClassName: 'jp-CloseAllIcon',
onClick: () => {
this.model.breakpoints = [];
this.cellsBreakpoints[this.getCell().id] = [];
this.removeAllGutterBreakpoints(this.getCell());
},
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[] } = {};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we change the name of this to cellBreakpoints where cell is singular, please?


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 => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking out loud: I was wondering whether there was a way to avoid the editor.editor pattern and use the editor wrapper instead (probably not since we need to access the CodeMirror methods directly)

editor.editor.setGutterMarker(line, 'breakpoints', null);
});
}

removeListner(cell: CodeCell) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: removeListner => removeListener

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does this edge case look like?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you set a breakpoint in line 1 and after that remove line 2 in editor gutter remove automatically breakpoint from line 1.

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;
}
}
class BreakpointsHeader extends Widget {
constructor(title: string) {
super({ node: document.createElement('header') });
Expand Down Expand Up @@ -103,13 +250,34 @@ export namespace Breakpoints {
}

set breakpoint(breakpoint: IBreakpoint) {
const index = this._state.findIndex(ele => ele.id === breakpoint.id);
const index = this._state.findIndex(ele => ele.line === breakpoint.line);
if (index !== -1) {
this._state[index] = breakpoint;
this._breakpointChanged.emit(breakpoint);
} else {
this.breakpoints = [...this.breakpoints, breakpoint];
}
}

removeBreakpoint(breakpoint: IBreakpoint) {
const breakpoints = this.breakpoints.filter(
ele => ele.line !== breakpoint.line
);
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);
Expand All @@ -118,26 +286,7 @@ export namespace Breakpoints {
/**
* Instantiation options for `Breakpoints`;
*/
export interface IOptions extends Panel.IOptions {}
}

const MOCK_BREAKPOINTS = [
{
id: 0,
active: true,
verified: true,
source: {
name: 'untitled.py'
},
line: 6
},
{
id: 1,
verified: true,
active: false,
source: {
name: 'untitled.py'
},
line: 7
export interface IOptions extends Panel.IOptions {
noteTracker?: INotebookTracker;
}
];
}
27 changes: 18 additions & 9 deletions src/debugger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,18 @@

import { IDataConnector } from '@jupyterlab/coreutils';

import { BoxPanel, TabPanel } from '@phosphor/widgets';
import { BoxPanel } from '@phosphor/widgets';

import { ReadonlyJSONValue, UUID } from '@phosphor/coreutils';

import { IDisposable } from '@phosphor/disposable';

import { DebuggerSidebar } from './sidebar';
import { INotebookTracker } from '@jupyterlab/notebook';
import { CodeCell } from '@jupyterlab/cells';
import { IEditorTracker } from '@jupyterlab/fileeditor';

export class Debugger extends BoxPanel {
readonly model: Debugger.Model;

readonly tabs = new TabPanel();

readonly sidebar: DebuggerSidebar;

constructor(options: Debugger.IOptions) {
super({ direction: 'left-to-right' });

Expand All @@ -26,10 +23,15 @@ export class Debugger extends BoxPanel {
this.title.label = 'Debugger';

this.addClass('jp-Debugger');
this.addWidget(this.tabs);
this.addWidget(this.sidebar);
}

readonly model: Debugger.Model;

readonly sidebar: DebuggerSidebar;

previousCell: CodeCell;

dispose(): void {
if (this.isDisposed) {
return;
Expand All @@ -45,14 +47,16 @@ export class Debugger extends BoxPanel {
export namespace Debugger {
export interface IOptions {
connector?: IDataConnector<ReadonlyJSONValue>;

noteTracker?: INotebookTracker;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand the reasoning here. Why does the Debugger need a reference to any trackers? The pattern I had in mind was the extension to have the trackers and as those trackers change for it to modify the debugger's handle to individual text editors.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In actual branch, i working on a split this. I get your idea before, these changes I made after the suggestion of Jeremy. I guess tomorrow or on Wednesday I will merge changes to this branch.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah okay, great; I'll take a look whenever you're ready for that!

editorTracker?: IEditorTracker;
id?: string;
}

export class Model implements IDisposable {
constructor(options: Debugger.Model.IOptions) {
this.connector = options.connector || null;
this.id = options.id || UUID.uuid4();
this._notebook = options.noteTracker;
void this._populate();
}

Expand All @@ -64,6 +68,10 @@ export namespace Debugger {
return this._isDisposed;
}

get notebookTracker() {
return this._notebook;
}

dispose(): void {
this._isDisposed = true;
}
Expand All @@ -77,6 +85,7 @@ export namespace Debugger {
}

private _isDisposed = false;
private _notebook: INotebookTracker;
}

export namespace Model {
Expand Down