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

Add life-cycle button in toolbar of notebook and console panel. #239

Merged
merged 7 commits into from
Dec 16, 2019
Merged
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
82 changes: 77 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ import {
JupyterFrontEndPlugin
} from '@jupyterlab/application';

import { IClientSession, ICommandPalette } from '@jupyterlab/apputils';
import {
IClientSession,
ICommandPalette,
Toolbar,
ToolbarButton
} from '@jupyterlab/apputils';

import { IEditorServices } from '@jupyterlab/codeeditor';

Expand Down Expand Up @@ -83,6 +88,57 @@ async function setDebugSession(
app.commands.notifyCommandChanged();
}

async function updateToolbar(
widget: NotebookPanel | ConsolePanel | DocumentWidget,
debug: IDebugger
) {
const isDebuggingEnabled = await debug.requestDebuggingEnabled();
if (!isDebuggingEnabled) {
return;
}

const toggleAttribute = () => {
if (debug.session.debuggedClients.has(debug.session.client.path)) {
widget.node.setAttribute('data-jp-debugger', 'true');
} else {
widget.node.removeAttribute('data-jp-debugger');
}
};

const getToolbar = (): Toolbar => {
jtpio marked this conversation as resolved.
Show resolved Hide resolved
if (!(widget instanceof ConsolePanel)) {
return widget.toolbar;
}
const toolbar = widget.widgets.find(w => w instanceof Toolbar) as Toolbar;
return toolbar ?? new Toolbar();
};

const toolbar = getToolbar();

const isToolbarNotExist = toolbar.addItem(
'debugger-lifeCycle-button',
new ToolbarButton({
className: 'jp-DebuggerSwitchButton',
iconClassName: 'jp-ToggleSwitch',
onClick: async () => {
if (!debug.session.debuggedClients.delete(debug.session.client.path)) {
debug.session.debuggedClients.add(debug.session.client.path);
await debug.start();
} else {
await debug.stop();
}
toggleAttribute();
},
tooltip: 'Enable / Disable Debugger'
})
);

if (isToolbarNotExist && widget instanceof ConsolePanel) {
widget.insertWidget(0, toolbar);
}
toggleAttribute();
}

class DebuggerHandler<
H extends ConsoleHandler | NotebookHandler | FileHandler
> {
Expand All @@ -93,22 +149,30 @@ class DebuggerHandler<
async update<W extends ConsolePanel | NotebookPanel | FileEditor>(
debug: IDebugger,
widget: W
) {
): Promise<void> {
const debuggingEnabled = await debug.requestDebuggingEnabled();
if (!debug.model || this.handlers[widget.id] || !debuggingEnabled) {
if (!debug.model || !debuggingEnabled || !debug.isStarted) {
return;
}

if (
this.handlers[widget.id] &&
!debug.session.debuggedClients.has(debug.session.client.path)
) {
return debug.stop();
}

const handler = new this.builder({
debuggerService: debug,
widget
});
widget.node.setAttribute('data-jp-debugger', 'true');

this.handlers[widget.id] = handler;

widget.disposed.connect(() => {
handler.dispose();
delete this.handlers[widget.id];
});

debug.model.disposed.connect(async () => {
const handlerIds = Object.keys(this.handlers);
if (handlerIds.length === 0) {
Expand All @@ -122,6 +186,10 @@ class DebuggerHandler<
});
this.handlers = {};
});

if (!debug.session.debuggedClients.has(debug.session.client.path)) {
return debug.stop();
}
}

private handlers: { [id: string]: H } = {};
Expand All @@ -145,6 +213,7 @@ const consoles: JupyterFrontEndPlugin<void> = {
}
await setDebugSession(app, debug, widget.session);
void handler.update(debug, widget);
void updateToolbar(widget, debug);
});
}
};
Expand All @@ -163,6 +232,7 @@ const files: JupyterFrontEndPlugin<void> = {
labShell: ILabShell
) => {
const handler = new DebuggerHandler<FileHandler>(FileHandler);

const activeSessions: {
[id: string]: Session.ISession;
} = {};
Expand Down Expand Up @@ -192,6 +262,7 @@ const files: JupyterFrontEndPlugin<void> = {
}
await setDebugSession(app, debug, session);
void handler.update(debug, content);
void updateToolbar(widget, debug);
} catch {
return;
}
Expand All @@ -216,6 +287,7 @@ const notebooks: JupyterFrontEndPlugin<void> = {
}
await setDebugSession(app, debug, widget.session);
void handler.update(debug, widget);
void updateToolbar(widget, debug);
});
}
};
Expand Down
11 changes: 10 additions & 1 deletion src/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,11 @@ export class DebugService implements IDebugger, IDisposable {
);
});
}
this._model.breakpoints.restoreBreakpoints(bpMap);

// able resotre breakpoints after realod if had before breakpoints and enable lifecycle debugging
if (bpMap.size > 0 && autoStart) {
this.session.debuggedClients.add(this.session.client.path);
}

const stoppedThreads = new Set(reply.body.stoppedThreads);
this._model.stoppedThreads = stoppedThreads;
Expand All @@ -231,6 +235,11 @@ export class DebugService implements IDebugger, IDisposable {
await this.start();
}

if (!this.session.debuggedClients.has(this.session.client.path)) {
return;
}

this._model.breakpoints.restoreBreakpoints(bpMap);
if (stoppedThreads.size !== 0) {
await this._getAllFrames();
} else {
Expand Down
5 changes: 5 additions & 0 deletions src/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ export class DebugSession implements IDebugger.ISession {
}
}

get debuggedClients(): Set<string> {
Copy link
Member

Choose a reason for hiding this comment

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

Does this mean that a debug session should keep track of multiple clients?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

this was only my suggestion. For now, we still tracking all clients which are have supported kernel.

Copy link
Member

Choose a reason for hiding this comment

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

Not sure yet the session is the preferred place to store such information.

But it would be fine to refactor that in a follow-up PR.

return this._statesClient;
}

/**
* Return the kernel info for the debug session, waiting for the
* kernel to be ready.
Expand Down Expand Up @@ -221,6 +225,7 @@ export class DebugSession implements IDebugger.ISession {
IDebugger.ISession.Event
>(this);
private _seq: number = 0;
private _statesClient: Set<string> = new Set();
}

/**
Expand Down
5 changes: 5 additions & 0 deletions src/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,11 @@ export namespace IDebugger {
*/
client: IClientSession | Session.ISession;

/**
* Set of clientes which have enabled debugging.
*/
debuggedClients: Set<string>;

/**
* Whether the debug session is started
*/
Expand Down
7 changes: 7 additions & 0 deletions style/console.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.jp-ConsolePanel::before {
content: none;
}

.jp-ConsolePanel .jp-Toolbar {
justify-content: flex-end;
}
43 changes: 43 additions & 0 deletions style/icons.css
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,46 @@
[data-jp-theme-light='false'] .jp-ViewBreakpointIcon {
background-image: url('icons/md-dark/view-breakpoint.svg');
}

.jp-DebuggerSwitchButton::before {
content: '';
width: 14px;
height: 14px;
background-position: left center;
background-repeat: no-repeat;
background-size: 14px;
margin-right: 4px;
background-image: var(--jp-icon-bug);
}

.jp-ToggleSwitch {
display: flex;
align-items: center;
cursor: pointer;
background-color: var(--jp-border-color1);
-webkit-transition: 0.4s;
transition: 0.4s;
border-radius: 34px;
width: 35px;
}

.jp-ToggleSwitch::before {
content: '';
height: 10px;
width: 10px;
margin-left: 5px;
margin-right: 50%;
background-color: white;
-webkit-transition: 0.4s;
transition: 0.4s;
border-radius: 50%;
}

[data-jp-debugger='true'] .jp-ToggleSwitch {
background-color: var(--jp-warn-color0);
}

[data-jp-debugger='true'] .jp-ToggleSwitch::before {
margin-left: 50%;
margin-right: 5px;
}
5 changes: 3 additions & 2 deletions style/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
@import './editor.css';
@import './callstack.css';
@import './variables.css';

@import './icons.css';
@import './sidebar.css';
@import './sources.css';
Expand All @@ -25,4 +24,6 @@
content: '\F0D7';
}

/* svg icons */
.jp-Document .jp-Toolbar {
justify-content: flex-end;
}