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

Extra breakpoint after typing with refresh kernel. #436

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
conda init bash
conda info -a
- name: Create the conda environment
run: conda create -n jupyterlab-debugger --yes --quiet -c conda-forge nodejs jupyterlab=2 xeus-python=0.7.1 ptvsd python=$PYTHON_VERSION
run: conda create -n jupyterlab-debugger --yes --quiet -c conda-forge nodejs jupyterlab=2 xeus=0.23.14 xeus-python=0.7.1 ptvsd python=$PYTHON_VERSION
env:
PYTHON_VERSION: '3.8'

Expand All @@ -35,9 +35,6 @@ jobs:
jlpm && jlpm run build
jupyter labextension link .

- name: Install libgbm1 to fix puppeteer
run: sudo apt-get install libgbm1

- name: Browser check
run: |
source "$CONDA/etc/profile.d/conda.sh"
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ __pycache__
.idea/
*.orig

default.profraw
lerna-debug.log
yarn-error.log

Expand Down
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ A kernel with support for debugging is required to be able to use the debugger.
It is generally recommended to create a new `conda` environment to install the dependencies:

```bash
conda create -n jupyterlab-debugger -c conda-forge xeus-python=0.7.1 notebook=6 jupyterlab=2 ptvsd
conda create -n jupyterlab-debugger -c conda-forge xeus=0.23.14 xeus-python=0.7.1 notebook=6 jupyterlab=2 ptvsd
conda activate jupyterlab-debugger
```

Expand All @@ -31,11 +31,25 @@ Then, run the following command to install the extension:
jupyter labextension install @jupyterlab/debugger
```

## Usage

For now `xeus-python` is the only Jupyter kernel that supports debugging. `xeus-python` can be selected from the JupyterLab launcher:

![xpython-launcher](https://user-images.githubusercontent.com/591645/75235047-f8080f00-57bb-11ea-80c1-d422b9ff4ad4.png)

Alternatively, it is also possible to switch to the `xpython` kernel using the kernel selection dialog:

![xpython-dialog](https://user-images.githubusercontent.com/591645/80113902-2bc8a080-8583-11ea-8a8c-c7c0932107ae.gif)

Enable the debugger, set breakpoints and step into the code:

![xpython-step](https://user-images.githubusercontent.com/591645/80114105-70ecd280-8583-11ea-82b1-ca2e84a4ae0f.gif)

## Development

```bash
# Create a new conda environment
conda create -n jupyterlab-debugger -c conda-forge nodejs xeus-python=0.7.1 ptvsd jupyterlab=2
conda create -n jupyterlab-debugger -c conda-forge nodejs xeus=0.23.14 xeus-python=0.7.1 ptvsd jupyterlab=2

# Activate the conda environment
conda activate jupyterlab-debugger
Expand Down
1 change: 1 addition & 0 deletions binder/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ dependencies:
- notebook=6
- ptvsd
- xeus-python=0.7.1
- xeus=0.23.14
2 changes: 1 addition & 1 deletion binder/postBuild
Original file line number Diff line number Diff line change
@@ -1 +1 @@
jupyter labextension install @jupyterlab/debugger@0.2.0 --debug
jupyter labextension install @jupyterlab/debugger@0.3.0-alpha.1 --debug
142 changes: 134 additions & 8 deletions examples/index.ipynb

Large diffs are not rendered by default.

43 changes: 20 additions & 23 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@jupyterlab/debugger",
"version": "0.2.0",
"version": "0.3.0-alpha.1",
"description": "JupyterLab - Debugger Extension",
"keywords": [
"jupyter",
Expand Down Expand Up @@ -38,13 +38,14 @@
"build": "tsc -b",
"clean": "rimraf lib && rimraf tsconfig.tsbuildinfo && rimraf tests/build",
"docs": "typedoc --options tdoptions.json --theme ../../typedoc-theme src",
"lint": "jlpm && jlpm run prettier && jlpm run tslint",
"eslint": "eslint . --ext .ts,.tsx,.js,.jsx --fix",
"eslint:check": "eslint . --ext .ts,.tsx,.js,.jsx",
"lint": "jlpm && jlpm run prettier && jlpm run eslint",
"lint:check": "jlpm run prettier:check && jlpm run eslint:check",
"prepublishOnly": "npm run build",
"prettier": "prettier --write '**/*{.ts,.tsx,.js,.jsx,.css,.json,.md}'",
"prettier:check": "prettier --list-different '**/*{.ts,.tsx,.js,.jsx,.css,.json,.md}'",
"test": "python tests/run-test.py",
"tslint": "tslint --fix -c tslint.json --project tsconfig.json '**/*{.ts,.tsx}'",
"tslint:check": "tslint -c tslint.json --project tsconfig.json '**/*{.ts,.tsx}'",
"watch": "tsc -b --watch"
},
"dependencies": {
Expand All @@ -56,13 +57,14 @@
"@jupyterlab/docregistry": "^2.0.0",
"@jupyterlab/fileeditor": "^2.0.0",
"@jupyterlab/launcher": "^2.0.0",
"@jupyterlab/observables": "^3.0.0",
"@jupyterlab/notebook": "^2.0.0",
"@jupyterlab/observables": "^3.0.0",
"@jupyterlab/services": "^5.0.0",
"@jupyterlab/settingregistry": "^2.0.0",
"@jupyterlab/ui-components": "^2.0.0",
"@lumino/algorithm": "^1.2.0",
"@lumino/coreutils": "^1.3.1",
"@lumino/datagrid": "^0.5.3",
"@lumino/disposable": "^1.2.0",
"@lumino/widgets": "^1.8.0",
"murmurhash-js": "^1.0.0",
Expand All @@ -72,40 +74,35 @@
"@babel/core": "^7.5.5",
"@babel/preset-env": "^7.7.6",
"@jupyterlab/testutils": "^2.0.0",
"@types/chai": "^4.2.7",
"@types/codemirror": "0.0.76",
"@types/jest": "^24.0.17",
"@types/murmurhash-js": "1.0.3",
"chai": "^4.2.0",
"@typescript-eslint/eslint-plugin": "^2.33.0",
"@typescript-eslint/parser": "^2.33.0",
"canvas": "^2.6.1",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.7.0",
"eslint-plugin-jest": "^23.8.2",
"eslint-plugin-prettier": "^3.1.1",
"eslint-plugin-react": "^7.19.0",
"husky": "^3.1.0",
"jest": "^24.9.0",
"jest": "^26.0.1",
"jest-junit": "^10.0.0",
"jest-raw-loader": "^1.0.1",
"jest-summary-reporter": "^0.0.2",
"lint-staged": "^9.5.0",
"prettier": "^1.19.1",
"rimraf": "~3.0.0",
"ts-jest": "^24",
"tslint": "^5.20.1",
"tslint-config-prettier": "^1.18.0",
"tslint-plugin-prettier": "^2.0.1",
"shell-quote": "^1.7.2",
"ts-jest": "^25.5.1",
"typedoc": "^0.15.4",
"typescript": "~3.7.3"
"typescript": "~3.9.2"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"**/*{.ts,.tsx,.js,.jsx,.css,.json,.md}": [
"jlpm run prettier",
"git add"
],
"src/**/*{.ts,.tsx}": [
"jlpm run tslint",
"git add"
]
},
"publishConfig": {
"access": "public"
},
Expand Down
52 changes: 50 additions & 2 deletions src/breakpoints/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,14 @@ import { IDebugger } from '../tokens';
* A model for a list of breakpoints.
*/
export class BreakpointsModel implements IDisposable {
/**
get oldPathFromCell(): Map<string, string> {
return this._oldPathFromCell;
}

set oldPathFromCell(value: Map<string, string>) {
this._oldPathFromCell = value;
}
/*
* Whether the model is disposed.
*/
get isDisposed(): boolean {
Expand Down Expand Up @@ -57,6 +64,18 @@ export class BreakpointsModel implements IDisposable {
Signal.clearData(this);
}

/**
* Remove breakpoints which are removed.
* That is, if path has empty array
*
*/
cleanBreakpointsMapAboutEmptyArray(): void {
Array.from(this._breakpoints.entries()).forEach(value => {
if (value[1].length === 0) {
this._breakpoints.delete(value[0]);
}
});
}
/**
* Set the breakpoints for a given id (path).
* @param id The code id (path).
Expand All @@ -66,7 +85,6 @@ export class BreakpointsModel implements IDisposable {
this._breakpoints.set(id, breakpoints);
this._changed.emit(breakpoints);
}

/**
* Get the breakpoints for a given id (path).
* @param id The code id (path).
Expand All @@ -85,8 +103,38 @@ export class BreakpointsModel implements IDisposable {
}

private _isDisposed = false;
private _oldPathFromCell = new Map<string, string>();
private _breakpoints = new Map<string, IDebugger.IBreakpoint[]>();
private _changed = new Signal<this, IDebugger.IBreakpoint[]>(this);
private _restored = new Signal<this, void>(this);
private _clicked = new Signal<this, IDebugger.IBreakpoint>(this);
}

/**
* Class for map states of current cell
*
*/
export class States {
constructor(idCell?: string, codeChanged?: boolean) {
this._idCell = idCell;
this._codeChanged = codeChanged;
}

get idCell(): string {
return this._idCell;
}

set idCell(value: string) {
this._idCell = value;
}
get codeChanged(): boolean {
return this._codeChanged;
}

set codeChanged(value: boolean) {
this._codeChanged = value;
}

private _idCell?: string;
private _codeChanged?: boolean;
}
2 changes: 1 addition & 1 deletion src/debugger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export namespace Debugger {

const { callstackCommands, editorServices, service } = options;

this.model = new DebuggerModel();
this.model = service.model as DebuggerModel;
this.service = service as DebuggerService;
this.service.model = this.model;

Expand Down
53 changes: 49 additions & 4 deletions src/handlers/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { Editor } from 'codemirror';

import { IDebugger } from '../tokens';

import { BreakpointsModel } from '../breakpoints/model';
import { BreakpointsModel, States } from '../breakpoints/model';

import { DebuggerModel } from '../model';

Expand All @@ -44,7 +44,7 @@ export class EditorHandler implements IDisposable {
this._path = options.path;
this._debuggerService = options.debuggerService;
this._editor = options.editor;

this._idCell = options.idCell;
this._onModelChanged();
this._debuggerService.modelChanged.connect(this._onModelChanged, this);

Expand All @@ -69,6 +69,7 @@ export class EditorHandler implements IDisposable {
* Dispose the handler.
*/
dispose(): void {
this._removeGutterAfterDelete();
if (this.isDisposed) {
return;
}
Expand All @@ -78,6 +79,30 @@ export class EditorHandler implements IDisposable {
Signal.clearData(this);
}

/**
* Get when something in cell is changed
*/
get codeChanged(): boolean {
return this._codeChanged;
}
/**
* Set when something in cell is changed
*/
set codeChanged(codeChanged: boolean) {
this._codeChanged = codeChanged;
}
/**
* Get current idCell
*/
get idCell(): string {
return this._idCell;
}
/**
* Set current idCell
*/
set idCell(idCell: string) {
this._idCell = idCell;
}
/**
* Handle when the debug model changes.
*/
Expand Down Expand Up @@ -124,6 +149,7 @@ export class EditorHandler implements IDisposable {
'breakpoints'
]);
editor.editor.on('gutterClick', this._onGutterClick);
editor.editor.on('beforeChange', this._beforeChanges);
}

/**
Expand All @@ -139,6 +165,7 @@ export class EditorHandler implements IDisposable {
editor.setOption('lineNumbers', false);
editor.editor.setOption('gutters', []);
editor.editor.off('gutterClick', this._onGutterClick);
editor.editor.off('beforeChange', this._beforeChanges);
}

/**
Expand All @@ -159,9 +186,13 @@ export class EditorHandler implements IDisposable {
void this._debuggerService.updateBreakpoints(
this._editor.model.value.text,
breakpoints,
this._path
this._path,
new States(this.idCell, this._codeChanged)
);
}
private _beforeChanges = () => {
this._codeChanged = true;
};

/**
* Handle a click on the gutter.
Expand All @@ -170,6 +201,7 @@ export class EditorHandler implements IDisposable {
*/
private _onGutterClick = (editor: Editor, lineNumber: number) => {
const info = editor.lineInfo(lineNumber);

if (!info || this._id !== this._debuggerService.session.connection.id) {
return;
}
Expand All @@ -190,10 +222,19 @@ export class EditorHandler implements IDisposable {
void this._debuggerService.updateBreakpoints(
this._editor.model.value.text,
breakpoints,
this._path
this._path,
new States(this._idCell, false)
);
};

private _removeGutterAfterDelete() {
void this._debuggerService.updateBreakpoints(
this._editor.model.value.text,
[],
this._path,
new States(this._idCell, false)
);
}
/**
* Add the breakpoints to the editor.
*/
Expand Down Expand Up @@ -241,6 +282,8 @@ export class EditorHandler implements IDisposable {

private _id: string;
private _path: string;
private _idCell: string;
private _codeChanged: boolean;
private _editor: CodeEditor.IEditor;
private _debuggerModel: DebuggerModel;
private _breakpointsModel: BreakpointsModel;
Expand Down Expand Up @@ -273,6 +316,8 @@ export namespace EditorHandler {
* An optional path to a source file.
*/
path?: string;

idCell?: string;
}

/**
Expand Down
Loading