Skip to content

Feature: Breakpoint implementation #61

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
59 changes: 59 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import { activateLspClient, deactivateLspClient } from "./lsp/client";
import { LanguageClient } from "vscode-languageclient/node";
import { canonicaliseLocation } from "./utils/misc";
import config from "./utils/config";
import { MessageHandler } from "./utils/messageHandler";
import { sendToFrontendWrapped } from "./commands/showPanel";
import Messages from "./utils/messages";

// TODO: Don't expose this object directly, create an interface via a wrapper class
export let client: LanguageClient;
Expand Down Expand Up @@ -77,6 +80,62 @@ export function activate(context: vscode.ExtensionContext) {
vscode.commands.executeCommand("source-academy.show-panel", route, url);
},
});

const debugConfig = vscode.workspace.getConfiguration('debug');
try {
if (debugConfig.get("allowBreakpointsEverywhere") === false) {
debugConfig.update("allowBreakpointsEverywhere", true, vscode.ConfigurationTarget.Global);
vscode.window.showInformationMessage('Successfully set "debug.allowBreakpointsEverywhere" to true in your user settings.');
}

} catch (error) {
// Handle potential errors, e.g., if settings can't be written.
console.error(error);
vscode.window.showErrorMessage([
'Failed to set "debug.allowBreakpointsEverywhere" to true in your user settings.',
'Please manually set this to true to be able to use the CSE Machine'
].join(" "));
}


let messageHandler = MessageHandler.getInstance()
// we use this map to track breakpoints
// breakpoint instances are the same even when they are moved
const m = new Map<vscode.SourceBreakpoint, number>()
const handle_breakpoints = (breakpoint: vscode.Breakpoint, add: boolean) => {
if (!(breakpoint instanceof vscode.SourceBreakpoint)) {
return
}
const line = breakpoint.location.range.start.line
const editor = messageHandler.activeEditor
if (editor && editor.uri.toString() === breakpoint.location.uri.toString()) {
// Check for change
if (m.has(breakpoint) && add) {
delete editor.breakpoints[m.get(breakpoint)!]
editor.breakpoints[line] = "ace_breakpoint"
m.set(breakpoint, line)
}
else {
if (add) {
m.set(breakpoint, line);
editor.breakpoints[line] = "ace_breakpoint";
}
else {
m.delete(breakpoint)
delete editor.breakpoints[line];
}
}
}
}

vscode.debug.onDidChangeBreakpoints((e: vscode.BreakpointsChangeEvent) => {
e.added.map(b => handle_breakpoints(b, true))
e.removed.map(b => handle_breakpoints(b, false))
e.changed.map(b => handle_breakpoints(b, true))
const editor = messageHandler.activeEditor;
if (editor)
sendToFrontendWrapped(Messages.SetEditorBreakpoints(editor.workspaceLocation, editor.breakpoints))
})
}

// This method is called when your extension is deactivated
Expand Down
9 changes: 9 additions & 0 deletions src/utils/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,25 @@ export class Editor {
assessmentName: string;
questionId: number;

// Data for breakpoints
breakpoints: string[];

private constructor(
editor: vscode.TextEditor,
prepend: string,
uri: string,
workspaceLocation: VscWorkspaceLocation,
assessmentName: string,
questionId: number,
breakpoints: string[],
) {
this.editor = editor;
this.prepend = prepend;
this.uri = uri;
this.workspaceLocation = workspaceLocation;
this.assessmentName = assessmentName;
this.questionId = questionId;
this.breakpoints = breakpoints;
}

/** For debugging purposes */
Expand All @@ -57,6 +62,7 @@ export class Editor {
questionId: number,
prepend: string = "",
initialCode: string = "",
breakpoints: string[]
): Promise<Editor> {
const workspaceFolder = canonicaliseLocation(config.workspaceFolder);
const filePath = path.join(
Expand Down Expand Up @@ -113,6 +119,7 @@ export class Editor {
viewColumn: vscode.ViewColumn.One,
});


// Programmatically set the language
vscode.languages.setTextDocumentLanguage(editor.document, "source");

Expand All @@ -131,6 +138,7 @@ export class Editor {
workspaceLocation,
assessmentName,
questionId,
breakpoints
);

// Register callback when contents changed
Expand All @@ -147,6 +155,7 @@ export class Editor {
},
);


return self;
}

Expand Down
23 changes: 23 additions & 0 deletions src/utils/messageHandler.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,28 @@ export class MessageHandler {
message.questionId,
message.prepend,
message.initialCode,
message.breakpoints
);


// Remove all breakpoints, then add the one included in the message
// Need this to pass typechecks
const editor = this.activeEditor
if (editor !== null) {
vscode.debug.removeBreakpoints(
vscode.debug.breakpoints.filter(bp =>
bp instanceof vscode.SourceBreakpoint
&& bp.location.uri.toString() === editor.uri.toString()
)
);
vscode.debug.addBreakpoints(this.activeEditor.breakpoints.map((s, index) => {
if (s === "ace_breakpoint") {
return new vscode.SourceBreakpoint(new vscode.Location(vscode.Uri.parse(editor.uri), new vscode.Position(index, 0)), true)
}
}).filter(x => x !== undefined));
}


this.activeEditor.uri;
const info = context.globalState.get("info") ?? {};
if (this.activeEditor.uri) {
Expand All @@ -130,6 +151,7 @@ export class MessageHandler {
);
const nPrependLines = getNumPrependLines(message.prepend);
_.set(info, `["${this.activeEditor.uri}"].prepend`, nPrependLines);

context.globalState.update("info", info);
client.sendRequest("source/publishInfo", info);
}
Expand Down Expand Up @@ -157,6 +179,7 @@ export class MessageHandler {
console.log(`Sending message: ${JSON.stringify(message)}`);
sendToFrontend(this.panel, message);
});

break;
case MessageTypeNames.NotifyAssessmentsOverview:
const { assessmentOverviews, courseId } = message;
Expand Down
6 changes: 6 additions & 0 deletions src/utils/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,15 @@ const Messages = createMessages({
chapter: number,
prepend: string,
initialCode: string,
breakpoints: string[],
) => ({
workspaceLocation,
assessmentName,
questionId,
chapter,
prepend,
initialCode,
breakpoints
}),
Text: (workspaceLocation: VscWorkspaceLocation, code: string) => ({
workspaceLocation,
Expand Down Expand Up @@ -92,6 +94,10 @@ const Messages = createMessages({
LoginWithBrowser: (route: string) => ({
route,
}),
SetEditorBreakpoints: (workspaceLocation: VscWorkspaceLocation, newBreakpoints: string[]) => ({
workspaceLocation,
newBreakpoints
})
});

export default Messages;
Expand Down