diff options
-rw-r--r-- | packages/bun-debug-adapter-protocol/src/debugger/adapter.ts | 27 | ||||
-rw-r--r-- | packages/bun-inspector-protocol/src/inspector/websocket.ts | 13 | ||||
-rw-r--r-- | packages/bun-vscode/.gitignore | 1 | ||||
-rw-r--r-- | packages/bun-vscode/example/example.test.ts | 4 | ||||
-rw-r--r-- | packages/bun-vscode/src/features/debug.ts | 63 |
5 files changed, 79 insertions, 29 deletions
diff --git a/packages/bun-debug-adapter-protocol/src/debugger/adapter.ts b/packages/bun-debug-adapter-protocol/src/debugger/adapter.ts index cd1b656a7..33555dbb0 100644 --- a/packages/bun-debug-adapter-protocol/src/debugger/adapter.ts +++ b/packages/bun-debug-adapter-protocol/src/debugger/adapter.ts @@ -109,7 +109,6 @@ export class DebugAdapter implements IDebugAdapter, InspectorListener { #initialized?: InitializeRequest; #launched?: LaunchRequest; #connected?: boolean; - #terminated?: boolean; constructor({ url, send, stdout, stderr, ...options }: DebugAdapterOptions) { this.#url = new URL(url); @@ -129,6 +128,10 @@ export class DebugAdapter implements IDebugAdapter, InspectorListener { this.#variables = [{ name: "", value: "", type: undefined, variablesReference: 0 }]; } + get inspector(): UnixWebSocketInspector { + return this.#inspector; + } + async accept(message: DAP.Request | DAP.Response | DAP.Event): Promise<void> { const { type } = message; @@ -414,7 +417,18 @@ export class DebugAdapter implements IDebugAdapter, InspectorListener { async #attach(request: AttachRequest): Promise<void> { const { url } = request; + if (this.#url.href === url) { + this.#emit("output", { + category: "debug console", + output: "Debugger attached.\n", + }); + + this.configurationDone(); + return; + } + if (await this.#start(url)) { + this.configurationDone(); return; } @@ -422,7 +436,6 @@ export class DebugAdapter implements IDebugAdapter, InspectorListener { } terminate(): void { - this.#terminated = true; this.#process?.kill(); } @@ -855,14 +868,6 @@ export class DebugAdapter implements IDebugAdapter, InspectorListener { output: "Debugger detached.\n", }); - if (error && !this.#terminated) { - const { message } = error; - this.#emit("output", { - category: "stderr", - output: `${message}\n`, - }); - } - this.#emit("terminated"); this.#reset(); } @@ -1426,7 +1431,6 @@ export class DebugAdapter implements IDebugAdapter, InspectorListener { } close(): void { - this.#terminated = true; this.#process?.kill(); this.#inspector.close(); this.#reset(); @@ -1444,7 +1448,6 @@ export class DebugAdapter implements IDebugAdapter, InspectorListener { this.#launched = undefined; this.#initialized = undefined; this.#connected = undefined; - this.#terminated = undefined; } } diff --git a/packages/bun-inspector-protocol/src/inspector/websocket.ts b/packages/bun-inspector-protocol/src/inspector/websocket.ts index 4ba85df13..238d3b2b7 100644 --- a/packages/bun-inspector-protocol/src/inspector/websocket.ts +++ b/packages/bun-inspector-protocol/src/inspector/websocket.ts @@ -224,14 +224,19 @@ export class WebSocketInspector implements Inspector { export class UnixWebSocketInspector extends WebSocketInspector { #unix: string; #server: Server; - #ready: Promise<void>; + #ready: Promise<unknown>; + startDebugging?: () => void; constructor(options: WebSocketInspectorOptions) { super(options); this.#unix = unixSocket(); this.#server = createServer(); this.#server.listen(this.#unix); - this.#ready = this.#wait(); + this.#ready = this.#wait().then(() => { + setTimeout(() => { + this.start().then(() => this.startDebugging?.()); + }, 1); + }); } get unix(): string { @@ -240,16 +245,18 @@ export class UnixWebSocketInspector extends WebSocketInspector { #wait(): Promise<void> { return new Promise(resolve => { + console.log("waiting"); this.#server.once("connection", socket => { + console.log("received"); socket.once("data", resolve); }); - setTimeout(resolve, 1000); }); } async start(url?: string | URL): Promise<boolean> { await this.#ready; try { + console.log("starting"); return await super.start(url); } finally { this.#ready = this.#wait(); diff --git a/packages/bun-vscode/.gitignore b/packages/bun-vscode/.gitignore index 9db2648e4..cafc85cea 100644 --- a/packages/bun-vscode/.gitignore +++ b/packages/bun-vscode/.gitignore @@ -1,2 +1,3 @@ node_modules extension +example/.vscode diff --git a/packages/bun-vscode/example/example.test.ts b/packages/bun-vscode/example/example.test.ts index eb15eed39..a9da929eb 100644 --- a/packages/bun-vscode/example/example.test.ts +++ b/packages/bun-vscode/example/example.test.ts @@ -3,5 +3,9 @@ import { describe, test, expect } from "bun:test"; describe("example", () => { test("it works", () => { expect(1).toBe(1); + expect(1).not.toBe(2); + expect(() => { + throw new Error("error"); + }).toThrow(); }); }); diff --git a/packages/bun-vscode/src/features/debug.ts b/packages/bun-vscode/src/features/debug.ts index bbfadb62e..eae2b1c33 100644 --- a/packages/bun-vscode/src/features/debug.ts +++ b/packages/bun-vscode/src/features/debug.ts @@ -11,7 +11,7 @@ const debugConfiguration: vscode.DebugConfiguration = { request: "launch", name: "Debug Bun", program: "${file}", - watch: true, + watch: false, }; const runConfiguration: vscode.DebugConfiguration = { @@ -20,7 +20,7 @@ const runConfiguration: vscode.DebugConfiguration = { name: "Run Bun", program: "${file}", debug: false, - watch: true, + watch: false, }; const attachConfiguration: vscode.DebugConfiguration = { @@ -30,7 +30,8 @@ const attachConfiguration: vscode.DebugConfiguration = { url: "ws://localhost:6499/", }; -const channels: Record<string, vscode.OutputChannel> = {}; +let channels: Record<string, vscode.OutputChannel> = {}; +let terminal: TerminalDebugSession | undefined; export default function (context: vscode.ExtensionContext, factory?: vscode.DebugAdapterDescriptorFactory) { context.subscriptions.push( @@ -50,10 +51,11 @@ export default function (context: vscode.ExtensionContext, factory?: vscode.Debu (channels["dap"] = vscode.window.createOutputChannel("Debug Adapter Protocol (Bun)")), (channels["jsc"] = vscode.window.createOutputChannel("JavaScript Inspector (Bun)")), (channels["console"] = vscode.window.createOutputChannel("Console (Bun)")), + (terminal = new TerminalDebugSession()), ); } -function RunFileCommand(resource: vscode.Uri): void { +function RunFileCommand(resource?: vscode.Uri): void { const path = getCurrentPath(resource); if (path) { vscode.debug.startDebugging(undefined, { @@ -64,7 +66,7 @@ function RunFileCommand(resource: vscode.Uri): void { } } -function DebugFileCommand(resource: vscode.Uri): void { +function DebugFileCommand(resource?: vscode.Uri): void { const path = getCurrentPath(resource); if (path) { vscode.debug.startDebugging(undefined, { @@ -105,19 +107,28 @@ class DebugConfigurationProvider implements vscode.DebugConfigurationProvider { class InlineDebugAdapterFactory implements vscode.DebugAdapterDescriptorFactory { createDebugAdapterDescriptor(session: vscode.DebugSession): ProviderResult<vscode.DebugAdapterDescriptor> { - const adapter = new VSCodeAdapter(session); + const { configuration } = session; + const { request, url } = configuration; + + if (request === "attach" && url === terminal?.url) { + return new vscode.DebugAdapterInlineImplementation(terminal); + } + + const adapter = new FileDebugSession(session.id); return new vscode.DebugAdapterInlineImplementation(adapter); } } -export class VSCodeAdapter extends DebugSession { - #adapter: DebugAdapter; +class FileDebugSession extends DebugSession { + readonly url: string; + readonly adapter: DebugAdapter; - constructor(session: vscode.DebugSession) { + constructor(sessionId?: string) { super(); - const { id } = session; - this.#adapter = new DebugAdapter({ - url: `ws+unix://${tmpdir()}/bun-vscode-${id}.sock`, + const uniqueId = sessionId ?? Math.random().toString(36).slice(2); + this.url = `ws+unix://${tmpdir()}/bun-vscode-${uniqueId}.sock`; + this.adapter = new DebugAdapter({ + url: this.url, send: this.sendMessage.bind(this), logger(...messages) { log("jsc", ...messages); @@ -147,11 +158,35 @@ export class VSCodeAdapter extends DebugSession { handleMessage(message: DAP.Event | DAP.Request | DAP.Response): void { log("dap", "<--", message); - this.#adapter.accept(message); + this.adapter.accept(message); } dispose() { - this.#adapter.close(); + this.adapter.close(); + } +} + +class TerminalDebugSession extends FileDebugSession { + readonly terminal: vscode.Terminal; + + constructor() { + super(); + this.terminal = vscode.window.createTerminal({ + name: "Bun Terminal", + env: { + "BUN_INSPECT": `1${this.url}`, + "BUN_INSPECT_NOTIFY": `unix://${this.adapter.inspector.unix}`, + }, + isTransient: true, + iconPath: new vscode.ThemeIcon("debug-console"), + }); + this.terminal.show(); + this.adapter.inspector.startDebugging = () => { + vscode.debug.startDebugging(undefined, { + ...attachConfiguration, + url: this.url, + }); + }; } } |