aboutsummaryrefslogtreecommitdiff
path: root/packages/bun-vscode/src/features/debug.ts
diff options
context:
space:
mode:
authorGravatar Ashcon Partovi <ashcon@partovi.net> 2023-08-26 02:34:25 -0700
committerGravatar GitHub <noreply@github.com> 2023-08-26 02:34:25 -0700
commit2a9e967fd1c766a718808d5a7fa779d74d44e62c (patch)
tree3bf4c059c03b9b561bc565ecf7cf21eaceae5353 /packages/bun-vscode/src/features/debug.ts
parent910daeff27ead119e15f35f6c1e0aa09d2aa7562 (diff)
downloadbun-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.ts209
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;
}