diff options
author | 2023-08-26 02:34:25 -0700 | |
---|---|---|
committer | 2023-08-26 02:34:25 -0700 | |
commit | 2a9e967fd1c766a718808d5a7fa779d74d44e62c (patch) | |
tree | 3bf4c059c03b9b561bc565ecf7cf21eaceae5353 /packages/bun-vscode/src/features/debug.ts | |
parent | 910daeff27ead119e15f35f6c1e0aa09d2aa7562 (diff) | |
download | bun-2a9e967fd1c766a718808d5a7fa779d74d44e62c.tar.gz bun-2a9e967fd1c766a718808d5a7fa779d74d44e62c.tar.zst bun-2a9e967fd1c766a718808d5a7fa779d74d44e62c.zip |
More improvements to debugger support (#4345)
* More fixes for dap
* More changes
* More changes 2
* More fixes
* Fix debugger.ts
* Bun Terminal
Diffstat (limited to 'packages/bun-vscode/src/features/debug.ts')
-rw-r--r-- | packages/bun-vscode/src/features/debug.ts | 209 |
1 files changed, 135 insertions, 74 deletions
diff --git a/packages/bun-vscode/src/features/debug.ts b/packages/bun-vscode/src/features/debug.ts index 3b841ea66..eae2b1c33 100644 --- a/packages/bun-vscode/src/features/debug.ts +++ b/packages/bun-vscode/src/features/debug.ts @@ -3,13 +3,15 @@ import type { CancellationToken, DebugConfiguration, ProviderResult, WorkspaceFo import type { DAP } from "../../../bun-debug-adapter-protocol"; import { DebugAdapter } from "../../../bun-debug-adapter-protocol"; import { DebugSession } from "@vscode/debugadapter"; +import { inspect } from "node:util"; +import { tmpdir } from "node:os"; const debugConfiguration: vscode.DebugConfiguration = { type: "bun", request: "launch", name: "Debug Bun", program: "${file}", - watch: true, + watch: false, }; const runConfiguration: vscode.DebugConfiguration = { @@ -17,117 +19,131 @@ const runConfiguration: vscode.DebugConfiguration = { request: "launch", name: "Run Bun", program: "${file}", - watch: true, + debug: false, + watch: false, }; const attachConfiguration: vscode.DebugConfiguration = { type: "bun", request: "attach", - name: "Attach to Bun", + name: "Attach Bun", url: "ws://localhost:6499/", }; -const debugConfigurations: vscode.DebugConfiguration[] = [debugConfiguration, attachConfiguration]; +let channels: Record<string, vscode.OutputChannel> = {}; +let terminal: TerminalDebugSession | undefined; export default function (context: vscode.ExtensionContext, factory?: vscode.DebugAdapterDescriptorFactory) { context.subscriptions.push( - vscode.commands.registerCommand("extension.bun.runFile", (resource: vscode.Uri) => { - let targetResource = resource; - if (!targetResource && vscode.window.activeTextEditor) { - targetResource = vscode.window.activeTextEditor.document.uri; - } - if (targetResource) { - vscode.debug.startDebugging(undefined, runConfiguration, { - noDebug: true, - }); - } - }), - vscode.commands.registerCommand("extension.bun.debugFile", (resource: vscode.Uri) => { - let targetResource = resource; - if (!targetResource && vscode.window.activeTextEditor) { - targetResource = vscode.window.activeTextEditor.document.uri; - } - if (targetResource) { - vscode.debug.startDebugging(undefined, { - ...debugConfiguration, - program: targetResource.fsPath, - }); - } - }), - ); - - const provider = new BunConfigurationProvider(); - context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider("bun", provider)); - - context.subscriptions.push( + vscode.commands.registerCommand("extension.bun.runFile", RunFileCommand), + vscode.commands.registerCommand("extension.bun.debugFile", DebugFileCommand), vscode.debug.registerDebugConfigurationProvider( "bun", - { - provideDebugConfigurations(folder: WorkspaceFolder | undefined): ProviderResult<DebugConfiguration[]> { - return debugConfigurations; - }, - }, + new DebugConfigurationProvider(), + vscode.DebugConfigurationProviderTriggerKind.Initial, + ), + vscode.debug.registerDebugConfigurationProvider( + "bun", + new DebugConfigurationProvider(), vscode.DebugConfigurationProviderTriggerKind.Dynamic, ), + vscode.debug.registerDebugAdapterDescriptorFactory("bun", factory ?? new InlineDebugAdapterFactory()), + (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()), ); +} - if (!factory) { - factory = new InlineDebugAdapterFactory(); +function RunFileCommand(resource?: vscode.Uri): void { + const path = getCurrentPath(resource); + if (path) { + vscode.debug.startDebugging(undefined, { + ...runConfiguration, + noDebug: true, + program: path, + }); } - context.subscriptions.push(vscode.debug.registerDebugAdapterDescriptorFactory("bun", factory)); - if ("dispose" in factory && typeof factory.dispose === "function") { - // @ts-ignore - context.subscriptions.push(factory); +} + +function DebugFileCommand(resource?: vscode.Uri): void { + const path = getCurrentPath(resource); + if (path) { + vscode.debug.startDebugging(undefined, { + ...debugConfiguration, + program: path, + }); } } -class BunConfigurationProvider implements vscode.DebugConfigurationProvider { +class DebugConfigurationProvider implements vscode.DebugConfigurationProvider { + provideDebugConfigurations(folder: WorkspaceFolder | undefined): ProviderResult<DebugConfiguration[]> { + return [debugConfiguration, runConfiguration, attachConfiguration]; + } + resolveDebugConfiguration( folder: WorkspaceFolder | undefined, config: DebugConfiguration, token?: CancellationToken, ): ProviderResult<DebugConfiguration> { - if (!config.type && !config.request && !config.name) { - const editor = vscode.window.activeTextEditor; - if (editor && isJavaScript(editor.document.languageId)) { - Object.assign(config, debugConfiguration); + let target: DebugConfiguration; + + const { request } = config; + if (request === "attach") { + target = attachConfiguration; + } else { + target = debugConfiguration; + } + + for (const [key, value] of Object.entries(target)) { + if (config[key] === undefined) { + config[key] = value; } } + return config; } } class InlineDebugAdapterFactory implements vscode.DebugAdapterDescriptorFactory { - createDebugAdapterDescriptor(_session: vscode.DebugSession): ProviderResult<vscode.DebugAdapterDescriptor> { - const adapter = new VSCodeAdapter(_session); + createDebugAdapterDescriptor(session: vscode.DebugSession): ProviderResult<vscode.DebugAdapterDescriptor> { + 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); } } -function isJavaScript(languageId: string): boolean { - return ( - languageId === "javascript" || - languageId === "javascriptreact" || - languageId === "typescript" || - languageId === "typescriptreact" - ); -} +class FileDebugSession extends DebugSession { + readonly url: string; + readonly adapter: DebugAdapter; -export class VSCodeAdapter extends DebugSession { - #adapter: DebugAdapter; - #dap: vscode.OutputChannel; - - constructor(session: vscode.DebugSession) { + constructor(sessionId?: string) { super(); - this.#dap = vscode.window.createOutputChannel("Debug Adapter Protocol"); - this.#adapter = new DebugAdapter({ - sendToAdapter: this.sendMessage.bind(this), + 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); + }, + stdout(message) { + log("console", message); + }, + stderr(message) { + log("console", message); + }, }); } sendMessage(message: DAP.Request | DAP.Response | DAP.Event): void { - console.log("[dap] -->", message); - this.#dap.appendLine("--> " + JSON.stringify(message)); + log("dap", "-->", message); const { type } = message; if (type === "response") { @@ -140,14 +156,59 @@ export class VSCodeAdapter extends DebugSession { } handleMessage(message: DAP.Event | DAP.Request | DAP.Response): void { - console.log("[dap] <--", message); - this.#dap.appendLine("<-- " + JSON.stringify(message)); + log("dap", "<--", message); - this.#adapter.accept(message); + this.adapter.accept(message); } dispose() { - this.#adapter.close(); - this.#dap.dispose(); + 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, + }); + }; + } +} + +function log(channel: string, ...message: unknown[]): void { + if (process.env.NODE_ENV === "development") { + console.log(`[${channel}]`, ...message); + channels[channel]?.appendLine(message.map(v => inspect(v)).join(" ")); + } +} + +function isJavaScript(languageId: string): boolean { + return ( + languageId === "javascript" || + languageId === "javascriptreact" || + languageId === "typescript" || + languageId === "typescriptreact" + ); +} + +function getCurrentPath(target?: vscode.Uri): string | undefined { + if (!target && vscode.window.activeTextEditor) { + target = vscode.window.activeTextEditor.document.uri; } + return target?.fsPath; } |