diff --git a/vscode/package.json b/vscode/package.json index ebeb9a68d..90c5d8e2f 100644 --- a/vscode/package.json +++ b/vscode/package.json @@ -153,6 +153,11 @@ "command": "rubyLsp.collectRubyLspInfo", "title": "Collect Ruby LSP information for issue reporting", "category": "Ruby LSP" + }, + { + "command": "rubyLsp.migrateLaunchConfiguration", + "title": "Migrate launch.json configurations from rdbg to ruby_lsp", + "category": "Ruby LSP" } ], "configuration": { diff --git a/vscode/src/common.ts b/vscode/src/common.ts index 061acae19..7652eccb3 100644 --- a/vscode/src/common.ts +++ b/vscode/src/common.ts @@ -29,6 +29,7 @@ export enum Command { NewMinitestFile = "rubyLsp.newMinitestFile", CollectRubyLspInfo = "rubyLsp.collectRubyLspInfo", StartServerInDebugMode = "rubyLsp.startServerInDebugMode", + MigrateLaunchConfiguration = "rubyLsp.migrateLaunchConfiguration", } export interface RubyInterface { diff --git a/vscode/src/debugger.ts b/vscode/src/debugger.ts index 7ddbf51ca..88b115174 100644 --- a/vscode/src/debugger.ts +++ b/vscode/src/debugger.ts @@ -347,10 +347,12 @@ export class Debugger } private logDebuggerMessage(message: string) { - const trimmedMessage = message.trimEnd(); - if (trimmedMessage.length > 0) { - LOG_CHANNEL.info(`[debugger]: ${trimmedMessage}`); - this.console.append(trimmedMessage); - } + // Log to Output panel: Messages here automatically get newlines appended. + // Trim trailing newlines to prevent unwanted blank lines in the output + LOG_CHANNEL.info(`[debugger]: ${message.trimEnd()}`); + + // Log to Debug Console: Unlike Output panel, this needs explicit newlines + // so we preserve the original message format including any newlines + this.console.append(message); } } diff --git a/vscode/src/rubyLsp.ts b/vscode/src/rubyLsp.ts index 6bc84d00e..3d66b587d 100644 --- a/vscode/src/rubyLsp.ts +++ b/vscode/src/rubyLsp.ts @@ -597,6 +597,68 @@ export class RubyLsp { }, ), ); + vscode.commands.registerCommand( + Command.MigrateLaunchConfiguration, + async () => { + const workspace = await this.showWorkspacePick(); + + if (!workspace) { + return; + } + + const launchConfig = + (vscode.workspace + .getConfiguration("launch") + ?.get("configurations") as any[]) || []; + + const updatedLaunchConfig = launchConfig.map((config: any) => { + if (config.type === "rdbg") { + if (config.request === "launch") { + const newConfig = { ...config }; + newConfig.type = "ruby_lsp"; + + if (newConfig.askParameters !== true) { + delete newConfig.rdbgPath; + delete newConfig.cwd; + delete newConfig.useBundler; + + const command = (newConfig.command || "").replace( + "${workspaceRoot}/", + "", + ); + const script = newConfig.script || ""; + const args = (newConfig.args || []).join(" "); + newConfig.program = `${command} ${script} ${args}`.trim(); + + delete newConfig.command; + delete newConfig.script; + delete newConfig.args; + delete newConfig.askParameters; + } + + return newConfig; + } else if (config.request === "attach") { + const newConfig = { ...config }; + newConfig.type = "ruby_lsp"; + // rdbg's `debugPort` could be a socket path, or port number, or host:port + // we don't do complex parsing here, just assume it's socket path + newConfig.debugSocketPath = config.debugPort; + + return newConfig; + } + } + return config; + }); + + await vscode.workspace + .getConfiguration("launch") + .update( + "configurations", + updatedLaunchConfig, + vscode.ConfigurationTarget.Workspace, + ); + }, + ); } // Get the current active workspace based on which file is opened in the editor