Skip to content

Commit

Permalink
Move initializeExecute into RunByLineController
Browse files Browse the repository at this point in the history
  • Loading branch information
roblourens committed Sep 3, 2021
1 parent 94a48d1 commit 959a412
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 137 deletions.
23 changes: 11 additions & 12 deletions src/client/debugger/jupyter/debuggingManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ export class DebuggingManager implements IExtensionSingleActivationService, IDeb
}

const controller = this.notebookToRunByLineController.get(cell.notebook);
if (controller && controller.debugCellUri?.toString() === cell.document.uri.toString()) {
if (controller && controller.debugCell.document.uri.toString() === cell.document.uri.toString()) {
controller.continue();
}
}),
Expand Down Expand Up @@ -323,6 +323,7 @@ export class DebuggingManager implements IExtensionSingleActivationService, IDeb
if (this.vscNotebook.activeNotebookEditor) {
const activeDoc = this.vscNotebook.activeNotebookEditor.document;

// TODO we apparently always have a kernel here, clean up typings
const kernel = await this.ensureKernelIsRunning(activeDoc);
const debug = this.getDebuggerByUri(activeDoc);

Expand All @@ -334,19 +335,17 @@ export class DebuggingManager implements IExtensionSingleActivationService, IDeb
});
if (notebook && notebook.session) {
debug.resolve(session);
const adapter = new KernelDebugAdapter(
session,
debug.document,
notebook.session,
this.commandManager,
this.fs,
kernel,
this.settings
);
const adapter = new KernelDebugAdapter(session, debug.document, notebook.session, this.fs, kernel);

if (config.__mode === KernelDebugMode.RunByLine && typeof config.__cellIndex === 'number') {
const cellUri = activeDoc.cellAt(config.__cellIndex).document.uri;
const controller = new RunByLineController(adapter, cellUri);
const cell = activeDoc.cellAt(config.__cellIndex);
const controller = new RunByLineController(
adapter,
cell,
this.commandManager,
kernel!,
this.settings
);
adapter.setDebuggingDelegate(controller);
this.notebookToRunByLineController.set(debug.document, controller);
}
Expand Down
149 changes: 35 additions & 114 deletions src/client/debugger/jupyter/kernelDebugAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,33 @@

'use strict';

import { KernelMessage } from '@jupyterlab/services';
import * as path from 'path';
import {
NotebookDocument,
DebugSession,
debug,
DebugAdapter,
NotebookCell,
DebugConfiguration,
DebugProtocolMessage,
DebugSession,
Event,
EventEmitter,
DebugProtocolMessage,
notebooks,
NotebookCellExecutionStateChangeEvent,
NotebookCell,
NotebookCellExecutionState,
DebugConfiguration,
Uri,
NotebookCellExecutionStateChangeEvent,
NotebookCellKind,
debug
NotebookDocument,
notebooks,
Uri
} from 'vscode';
import { DebugProtocol } from 'vscode-debugprotocol';
import * as path from 'path';
import { IJupyterSession } from '../../datascience/types';
import { KernelMessage } from '@jupyterlab/services';
import { ICommandManager } from '../../common/application/types';
import { traceError, traceVerbose } from '../../common/logger';
import { IFileSystem } from '../../common/platform/types';
import { DebuggingDelegate, IKernelDebugAdapter } from '../types';
import { IConfigurationService, IDisposable } from '../../common/types';
import { Commands } from '../../datascience/constants';
import { IDisposable } from '../../common/types';
import { IKernel } from '../../datascience/jupyter/kernels/types';
import { IJupyterSession } from '../../datascience/types';
import { sendTelemetryEvent } from '../../telemetry';
import { DebuggingTelemetry } from '../constants';
import { parseForComments } from '../../../datascience-ui/common';
import { noop } from '../../common/utils/misc';
import { DebuggingDelegate, IKernelDebugAdapter } from '../types';

interface dumpCellResponse {
sourcePath: string; // filename for the dumped source
Expand Down Expand Up @@ -95,10 +91,8 @@ export class KernelDebugAdapter implements DebugAdapter, IKernelDebugAdapter, ID
private session: DebugSession,
private notebookDocument: NotebookDocument,
private readonly jupyterSession: IJupyterSession,
private commandManager: ICommandManager,
private fs: IFileSystem,
private readonly kernel: IKernel | undefined,
private settings: IConfigurationService
private readonly kernel: IKernel | undefined
) {
void this.dumpAllCells();

Expand All @@ -114,18 +108,14 @@ export class KernelDebugAdapter implements DebugAdapter, IKernelDebugAdapter, ID
sendTelemetryEvent(DebuggingTelemetry.successfullyStartedRunAndDebugCell);
}

if (configuration.__mode === KernelDebugMode.RunByLine) {
sendTelemetryEvent(DebuggingTelemetry.successfullyStartedRunByLine);
}

this.disposables.push(
this.jupyterSession.onIOPubMessage(async (msg: KernelMessage.IIOPubMessage) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const anyMsg = msg as any;

if (anyMsg.header.msg_type === 'debug_event') {
this.trace('event', JSON.stringify(msg));
if (!(await this.delegate?.willSendMessage(anyMsg))) {
if (!(await this.delegate?.willSendEvent(anyMsg))) {
this.sendMessage.fire(msg.content);
}
}
Expand Down Expand Up @@ -185,7 +175,12 @@ export class KernelDebugAdapter implements DebugAdapter, IKernelDebugAdapter, ID
if (message.type === 'request' && (message as DebugProtocol.Request).command === 'setBreakpoints') {
const args = (message as DebugProtocol.Request).arguments;
if (args.source && args.source.path && args.source.path.indexOf('vscode-notebook-cell:') === 0) {
await this.dumpCell(args.source.path);
const cell = this.notebookDocument
.getCells()
.find((c) => c.document.uri.toString() === args.source.path);
if (cell) {
await this.dumpCell(cell.index);
}
}
}

Expand All @@ -197,14 +192,8 @@ export class KernelDebugAdapter implements DebugAdapter, IKernelDebugAdapter, ID
await this.debugInfo();
}

// initialize Run By Line
if (
(this.configuration.__mode === KernelDebugMode.RunByLine ||
this.configuration.__mode === KernelDebugMode.Cell) &&
message.type === 'request' &&
(message as DebugProtocol.Request).command === 'configurationDone'
) {
await this.initializeExecute(message.seq);
if (message.type === 'request') {
await this.delegate?.willSendRequest(message as DebugProtocol.Request);
}

this.sendRequestToJupyterSession(message);
Expand Down Expand Up @@ -236,16 +225,14 @@ export class KernelDebugAdapter implements DebugAdapter, IKernelDebugAdapter, ID
});
}

public stackTrace(args?: {
threadId: number;
startFrame?: number;
levels?: number;
}): Thenable<DebugProtocol.StackTraceResponse['body']> {
return this.session.customRequest('stackTrace', {
threadId: args?.threadId,
startFrame: args?.startFrame,
levels: args?.levels
});
public stackTrace(args: DebugProtocol.StackTraceArguments): Thenable<DebugProtocol.StackTraceResponse['body']> {
return this.session.customRequest('stackTrace', args);
}

public setBreakpoints(
args: DebugProtocol.SetBreakpointsArguments
): Thenable<DebugProtocol.SetBreakpointsResponse['body']> {
return this.session.customRequest('setBreakpoints', args);
}

private scopes(frameId: number): void {
Expand All @@ -259,14 +246,14 @@ export class KernelDebugAdapter implements DebugAdapter, IKernelDebugAdapter, ID
private dumpAllCells() {
this.notebookDocument.getCells().forEach((cell) => {
if (cell.kind === NotebookCellKind.Code) {
void this.dumpCell(cell.document.uri.toString());
void this.dumpCell(cell.index);
}
});
}

// Dump content of given cell into a tmp file and return path to file.
private async dumpCell(uri: string): Promise<void> {
const cell = this.notebookDocument.getCells().find((c) => c.document.uri.toString() === uri);
public async dumpCell(index: number): Promise<void> {
const cell = this.notebookDocument.cellAt(index);
if (cell) {
try {
const response = await this.session.customRequest('dumpCell', { code: cell.document.getText() });
Expand Down Expand Up @@ -455,70 +442,4 @@ export class KernelDebugAdapter implements DebugAdapter, IKernelDebugAdapter, ID
break;
}
}

private async initializeExecute(seq: number) {
// remove this if when https://github.com/microsoft/debugpy/issues/706 is fixed and ipykernel ships it
// executing this code restarts debugpy and fixes https://github.com/microsoft/vscode-jupyter/issues/7251
if (this.kernel) {
const code = 'import debugpy\ndebugpy.debug_this_thread()';
await this.kernel.executeHidden(code, this.notebookDocument);
}

// put breakpoint at the beginning of the cell
const cellIndex = Number(this.configuration.__cellIndex);
const cell = this.notebookDocument.cellAt(cellIndex);

await this.dumpCell(cell.document.uri.toString());

if (this.configuration.__mode === KernelDebugMode.RunByLine) {
// This will save the code lines of the cell in lineList (so ignore comments and emtpy lines)
// Its done to set the Run by Line breakpoint on the first code line
const textLines = cell.document.getText().splitLines({ trim: false, removeEmptyEntries: false });
const lineList: number[] = [];
parseForComments(
textLines,
() => noop(),
(s, i) => {
if (s.trim().length !== 0) {
lineList.push(i);
}
}
);
lineList.sort();

// Don't send the SetBreakpointsRequest or open the variable view if there are no code lines
if (lineList.length !== 0) {
const initialBreakpoint: DebugProtocol.SourceBreakpoint = {
line: lineList[0] + 1
};
const message: DebugProtocol.SetBreakpointsRequest = {
seq: seq + 1,
type: 'request',
command: 'setBreakpoints',
arguments: {
source: {
name: path.basename(cell.notebook.uri.path),
path: cell.document.uri.toString()
},
lines: [lineList[0] + 1],
breakpoints: [initialBreakpoint],
sourceModified: false
}
};
this.sendRequestToJupyterSession(message);

// Open variable view
const settings = this.settings.getSettings();
if (settings.showVariableViewWhenDebugging) {
void this.commandManager.executeCommand(Commands.OpenVariableView);
}
}
}

// Run cell
void this.commandManager.executeCommand('notebook.cell.execute', {
ranges: [{ start: cell.index, end: cell.index + 1 }],
document: cell.document.uri
});
}
}
86 changes: 82 additions & 4 deletions src/client/debugger/jupyter/runByLineController.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,32 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import { DebugProtocolMessage, Uri } from 'vscode';
import * as path from 'path';
import { DebugProtocolMessage, NotebookCell } from 'vscode';
import { DebugProtocol } from 'vscode-debugprotocol';
import { parseForComments } from '../../../datascience-ui/common';
import { ICommandManager } from '../../common/application/types';
import { traceVerbose } from '../../common/logger';
import { IConfigurationService } from '../../common/types';
import { noop } from '../../common/utils/misc';
import { Commands } from '../../datascience/constants';
import { IKernel } from '../../datascience/jupyter/kernels/types';
import { sendTelemetryEvent } from '../../telemetry';
import { DebuggingTelemetry } from '../constants';
import { DebuggingDelegate, IKernelDebugAdapter } from '../types';

export class RunByLineController implements DebuggingDelegate {
private lastPausedThreadId: number | undefined;

constructor(private readonly debugAdapter: IKernelDebugAdapter, public readonly debugCellUri: Uri) {}
constructor(
private readonly debugAdapter: IKernelDebugAdapter,
public readonly debugCell: NotebookCell,
private readonly commandManager: ICommandManager,
private readonly kernel: IKernel,
private readonly settings: IConfigurationService
) {
sendTelemetryEvent(DebuggingTelemetry.successfullyStartedRunByLine);
}

public continue(): void {
if (typeof this.lastPausedThreadId !== 'number') {
Expand All @@ -23,7 +41,7 @@ export class RunByLineController implements DebuggingDelegate {
this.debugAdapter.disconnect();
}

public async willSendMessage(msg: DebugProtocolMessage): Promise<boolean> {
public async willSendEvent(msg: DebugProtocolMessage): Promise<boolean> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const anyMsg = msg as any;

Expand All @@ -38,6 +56,12 @@ export class RunByLineController implements DebuggingDelegate {
return false;
}

public async willSendRequest(request: DebugProtocol.Request): Promise<void> {
if (request.command === 'configurationDone') {
await this.initializeExecute();
}
}

private async handleStoppedEvent(threadId: number): Promise<boolean> {
if (await this.shouldStepIn(threadId)) {
void this.debugAdapter.stepIn(threadId);
Expand All @@ -53,10 +77,64 @@ export class RunByLineController implements DebuggingDelegate {
const stResponse = await this.debugAdapter.stackTrace({ threadId, startFrame: 0, levels: 1 });

const sf = stResponse.stackFrames[0];
return !!sf.source && sf.source.path !== this.debugCellUri.toString();
return !!sf.source && sf.source.path !== this.debugCell.document.uri.toString();
}

private trace(tag: string, msg: string) {
traceVerbose(`[Debug-RBL] ${tag}: ${msg}`);
}

private async initializeExecute() {
// remove this if when https://github.com/microsoft/debugpy/issues/706 is fixed and ipykernel ships it
// executing this code restarts debugpy and fixes https://github.com/microsoft/vscode-jupyter/issues/7251
if (this.kernel) {
const code = 'import debugpy\ndebugpy.debug_this_thread()';
await this.kernel.executeHidden(code, this.debugCell.notebook);
}

// put breakpoint at the beginning of the cell
await this.debugAdapter.dumpCell(this.debugCell.index);

// This will save the code lines of the cell in lineList (so ignore comments and emtpy lines)
// Its done to set the Run by Line breakpoint on the first code line
const textLines = this.debugCell.document.getText().splitLines({ trim: false, removeEmptyEntries: false });
const lineList: number[] = [];
parseForComments(
textLines,
() => noop(),
(s, i) => {
if (s.trim().length !== 0) {
lineList.push(i);
}
}
);
lineList.sort();

// Don't send the SetBreakpointsRequest or open the variable view if there are no code lines
if (lineList.length !== 0) {
const initialBreakpoint: DebugProtocol.SourceBreakpoint = {
line: lineList[0] + 1
};
await this.debugAdapter.setBreakpoints({
source: {
name: path.basename(this.debugCell.notebook.uri.path),
path: this.debugCell.document.uri.toString()
},
breakpoints: [initialBreakpoint],
sourceModified: false
});

// Open variable view
const settings = this.settings.getSettings();
if (settings.showVariableViewWhenDebugging) {
void this.commandManager.executeCommand(Commands.OpenVariableView);
}
}

// Run cell
void this.commandManager.executeCommand('notebook.cell.execute', {
ranges: [{ start: this.debugCell.index, end: this.debugCell.index + 1 }],
document: this.debugCell.document.uri
});
}
}
Loading

0 comments on commit 959a412

Please sign in to comment.