Skip to content
Draft
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
28 changes: 27 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"categories": [
"Programming Languages",
"Snippets",
"Formatters"
"Formatters",
"Debuggers"
],
"keywords": [
"cairo",
Expand Down Expand Up @@ -87,6 +88,31 @@
"category": "Cairo"
}
],
"breakpoints": [
{
"language": "cairo"
}
],
"debuggers": [
{
"type": "cairo",
"languages": [
"cairo"
],
"label": "Cairo Debug",
"configurationAttributes": {
"launch": {
"properties": {
"program": {
"type": "string",
"description": "Program to run to start debugging",
"default": "cairo-debugger"
}
}
}
}
}
],
"menus": {
"commandPalette": [
{
Expand Down
55 changes: 55 additions & 0 deletions src/debugger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import * as vscode from "vscode";
import { Context } from "./context";
import { ChildProcess, spawn } from "child_process";
import * as readline from "node:readline";
import { Readable } from "node:stream";

export function enableLaunchingDebugger(ctx: Context) {
const factory = new CairoDebugAdapterServerDescriptorFactory();
ctx.extension.subscriptions.push(
vscode.debug.registerDebugAdapterDescriptorFactory("cairo", factory),
);
}

class CairoDebugAdapterServerDescriptorFactory implements vscode.DebugAdapterDescriptorFactory {
private debugAdapterProcesses: ChildProcess[] = [];

createDebugAdapterDescriptor(
session: vscode.DebugSession,
): vscode.ProviderResult<vscode.DebugAdapterDescriptor> {
const program = session.configuration["program"] as string;
const adapterProcess = spawn(program, { stdio: "pipe", env: process.env });
this.debugAdapterProcesses.push(adapterProcess);

return this.waitForFreePort(adapterProcess.stdout).then(
(port) => new vscode.DebugAdapterServer(port),
);
}
Comment on lines +17 to +27
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
createDebugAdapterDescriptor(
session: vscode.DebugSession,
): vscode.ProviderResult<vscode.DebugAdapterDescriptor> {
const program = session.configuration["program"] as string;
const adapterProcess = spawn(program, { stdio: "pipe", env: process.env });
this.debugAdapterProcesses.push(adapterProcess);
return this.waitForFreePort(adapterProcess.stdout).then(
(port) => new vscode.DebugAdapterServer(port),
);
}
async createDebugAdapterDescriptor(
session: vscode.DebugSession,
): vscode.ProviderResult<vscode.DebugAdapterDescriptor> {
const program = session.configuration["program"] as string;
const adapterProcess = spawn(program, { stdio: "pipe", env: process.env });
this.debugAdapterProcesses.push(adapterProcess);
const port = await this.waitForFreePort(adapterProcess.stdout)
return new vscode.DebugAdapterServer(port);
}


async waitForFreePort(adapterStdout: Readable): Promise<number> {
const lineReader = readline.createInterface({ input: adapterStdout });

// Wait for the server to print the port number it is listening on.
for await (let line of lineReader) {
line = line.trim();
const matches = line.match("DEBUGGER PORT: ([0-9]*)");
if (matches !== null) {
const port = parseInt(matches[1]!, 10);
return Promise.resolve(port);
}
}

throw Error("Have not received a port number from the adapter");
}

dispose(): void {
for (const process of this.debugAdapterProcesses) {
process.kill();
}

for (const process of this.debugAdapterProcesses) {
// For good measure.
if (process.exitCode === undefined) process.kill("SIGKILL");
}
}
}
3 changes: 3 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ import * as vscode from "vscode";
import * as lc from "vscode-languageclient/node";
import { Context } from "./context";
import { CairoExtensionManager } from "./extensionManager";
import { enableLaunchingDebugger } from "./debugger";

export async function activate(extensionContext: vscode.ExtensionContext) {
const ctx = Context.create(extensionContext);

enableLaunchingDebugger(ctx);

if (ctx.config.get("enableLanguageServer")) {
const extensionManager = CairoExtensionManager.fromContext(ctx);
await extensionManager.tryStartClient();
Expand Down
Loading