about summary refs log tree commit diff
path: root/src/tools/rust-analyzer/editors/code
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-08-05 14:21:45 +0000
committerbors <bors@rust-lang.org>2024-08-05 14:21:45 +0000
commit64cd3da35da3c2e6f8cb7337667208d734ce4fdb (patch)
treea3a6e4c146ac439308976d9aa2b808df98674788 /src/tools/rust-analyzer/editors/code
parent7dd258a36d4a303e43f0ae4cbb7eea5bb40012e5 (diff)
parentd95a4b8d2bed8e2229c4815a2c6be6b625485fc2 (diff)
downloadrust-64cd3da35da3c2e6f8cb7337667208d734ce4fdb.tar.gz
rust-64cd3da35da3c2e6f8cb7337667208d734ce4fdb.zip
Auto merge of #17772 - Veykril:debug.ts, r=Veykril
internal: Reorganize debug.ts
Diffstat (limited to 'src/tools/rust-analyzer/editors/code')
-rw-r--r--src/tools/rust-analyzer/editors/code/src/debug.ts268
-rw-r--r--src/tools/rust-analyzer/editors/code/src/run.ts16
-rw-r--r--src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts2
3 files changed, 187 insertions, 99 deletions
diff --git a/src/tools/rust-analyzer/editors/code/src/debug.ts b/src/tools/rust-analyzer/editors/code/src/debug.ts
index d9622b4a0d2..3aae0f9ce6e 100644
--- a/src/tools/rust-analyzer/editors/code/src/debug.ts
+++ b/src/tools/rust-analyzer/editors/code/src/debug.ts
@@ -7,21 +7,15 @@ import { Cargo } from "./toolchain";
 import type { Ctx } from "./ctx";
 import { prepareEnv } from "./run";
 import { execute, isCargoRunnableArgs, unwrapUndefinable } from "./util";
+import type { Config } from "./config";
 
 const debugOutput = vscode.window.createOutputChannel("Debug");
-type DebugConfigProvider = (
-    runnable: ra.Runnable,
-    runnableArgs: ra.CargoRunnableArgs,
-    executable: string,
-    env: Record<string, string>,
-    sourceFileMap?: Record<string, string>,
-) => vscode.DebugConfiguration;
 
 export async function makeDebugConfig(ctx: Ctx, runnable: ra.Runnable): Promise<void> {
     const scope = ctx.activeRustEditor?.document.uri;
     if (!scope) return;
 
-    const debugConfig = await getDebugConfiguration(ctx, runnable);
+    const debugConfig = await getDebugConfiguration(ctx.config, runnable, false);
     if (!debugConfig) return;
 
     const wsLaunchSection = vscode.workspace.getConfiguration("launch", scope);
@@ -57,7 +51,7 @@ export async function startDebugSession(ctx: Ctx, runnable: ra.Runnable): Promis
         message = " (from launch.json)";
         debugOutput.clear();
     } else {
-        debugConfig = await getDebugConfiguration(ctx, runnable);
+        debugConfig = await getDebugConfiguration(ctx.config, runnable);
     }
 
     if (!debugConfig) return false;
@@ -74,35 +68,35 @@ function createCommandLink(extensionId: string): string {
 }
 
 async function getDebugConfiguration(
-    ctx: Ctx,
+    config: Config,
     runnable: ra.Runnable,
+    inheritEnv: boolean = true,
 ): Promise<vscode.DebugConfiguration | undefined> {
     if (!isCargoRunnableArgs(runnable.args)) {
         return;
     }
     const runnableArgs: ra.CargoRunnableArgs = runnable.args;
 
-    const editor = ctx.activeRustEditor;
-    if (!editor) return;
+    const debugOptions = config.debug;
 
-    const knownEngines: Record<string, DebugConfigProvider> = {
-        "vadimcn.vscode-lldb": getCodeLldbDebugConfig,
-        "ms-vscode.cpptools": getCCppDebugConfig,
-        "webfreak.debug": getNativeDebugConfig,
-    };
-    const debugOptions = ctx.config.debug;
+    let provider: null | KnownEnginesType = null;
 
-    let debugEngine = null;
     if (debugOptions.engine === "auto") {
-        for (var engineId in knownEngines) {
-            debugEngine = vscode.extensions.getExtension(engineId);
-            if (debugEngine) break;
+        for (const engineId in knownEngines) {
+            const debugEngine = vscode.extensions.getExtension(engineId);
+            if (debugEngine) {
+                provider = knownEngines[engineId as keyof typeof knownEngines];
+                break;
+            }
         }
     } else if (debugOptions.engine) {
-        debugEngine = vscode.extensions.getExtension(debugOptions.engine);
+        const debugEngine = vscode.extensions.getExtension(debugOptions.engine);
+        if (debugEngine && Object.keys(knownEngines).includes(debugOptions.engine)) {
+            provider = knownEngines[debugOptions.engine as keyof typeof knownEngines];
+        }
     }
 
-    if (!debugEngine) {
+    if (!provider) {
         const commandCCpp: string = createCommandLink("ms-vscode.cpptools");
         const commandCodeLLDB: string = createCommandLink("vadimcn.vscode-lldb");
         const commandNativeDebug: string = createCommandLink("webfreak.debug");
@@ -116,7 +110,7 @@ async function getDebugConfiguration(
     }
 
     debugOutput.clear();
-    if (ctx.config.debug.openDebugPane) {
+    if (config.debug.openDebugPane) {
         debugOutput.show(true);
     }
     // folder exists or RA is not active.
@@ -131,37 +125,36 @@ async function getDebugConfiguration(
               firstWorkspace;
 
     const workspace = unwrapUndefinable(maybeWorkspace);
-    const wsFolder = path.normalize(workspace.uri.fsPath);
+    let wsFolder = path.normalize(workspace.uri.fsPath);
+    if (os.platform() === "win32") {
+        // in windows, the drive letter can vary in casing for VSCode, so we gotta normalize that first
+        wsFolder = wsFolder.replace(/^[a-z]:\\/, (c) => c.toUpperCase());
+    }
+
     const workspaceQualifier = isMultiFolderWorkspace ? `:${workspace.name}` : "";
     function simplifyPath(p: string): string {
+        // in windows, the drive letter can vary in casing for VSCode, so we gotta normalize that first
+        if (os.platform() === "win32") {
+            p = p.replace(/^[a-z]:\\/, (c) => c.toUpperCase());
+        }
         // see https://github.com/rust-lang/rust-analyzer/pull/5513#issuecomment-663458818 for why this is needed
         return path.normalize(p).replace(wsFolder, `\${workspaceFolder${workspaceQualifier}}`);
     }
 
-    const env = prepareEnv(runnable.label, runnableArgs, ctx.config.runnablesExtraEnv);
+    const env = prepareEnv(inheritEnv, runnable.label, runnableArgs, config.runnablesExtraEnv);
     const executable = await getDebugExecutable(runnableArgs, env);
     let sourceFileMap = debugOptions.sourceFileMap;
     if (sourceFileMap === "auto") {
         sourceFileMap = {};
-        const sysroot = env["RUSTC_TOOLCHAIN"];
-        if (sysroot) {
-            // let's try to use the default toolchain
-            const data = await execute(`rustc -V -v`, { cwd: wsFolder, env });
-            const rx = /commit-hash:\s(.*)$/m;
-
-            const commitHash = rx.exec(data)?.[1];
-            if (commitHash) {
-                const rustlib = path.normalize(sysroot + "/lib/rustlib/src/rust");
-                sourceFileMap[`/rustc/${commitHash}/`] = rustlib;
-            }
-        }
+        await discoverSourceFileMap(sourceFileMap, env, wsFolder);
     }
 
-    const provider = unwrapUndefinable(knownEngines[debugEngine.id]);
-    const debugConfig = provider(
+    const debugConfig = getDebugConfig(
+        provider,
+        simplifyPath,
         runnable,
         runnableArgs,
-        simplifyPath(executable),
+        executable,
         env,
         sourceFileMap,
     );
@@ -186,6 +179,92 @@ async function getDebugConfiguration(
     return debugConfig;
 }
 
+async function discoverSourceFileMap(
+    sourceFileMap: Record<string, string>,
+    env: Record<string, string>,
+    cwd: string,
+) {
+    const sysroot = env["RUSTC_TOOLCHAIN"];
+    if (sysroot) {
+        // let's try to use the default toolchain
+        const data = await execute(`rustc -V -v`, { cwd, env });
+        const rx = /commit-hash:\s(.*)$/m;
+
+        const commitHash = rx.exec(data)?.[1];
+        if (commitHash) {
+            const rustlib = path.normalize(sysroot + "/lib/rustlib/src/rust");
+            sourceFileMap[`/rustc/${commitHash}/`] = rustlib;
+        }
+    }
+}
+
+type PropertyFetcher<Config, Input, Key extends keyof Config> = (
+    input: Input,
+) => [Key, Config[Key]];
+
+type DebugConfigProvider<Type extends string, DebugConfig extends BaseDebugConfig<Type>> = {
+    executableProperty: keyof DebugConfig;
+    environmentProperty: PropertyFetcher<DebugConfig, Record<string, string>, keyof DebugConfig>;
+    runnableArgsProperty: PropertyFetcher<DebugConfig, ra.CargoRunnableArgs, keyof DebugConfig>;
+    sourceFileMapProperty?: keyof DebugConfig;
+    type: Type;
+    additional?: Record<string, unknown>;
+};
+
+type KnownEnginesType = (typeof knownEngines)[keyof typeof knownEngines];
+const knownEngines: {
+    "vadimcn.vscode-lldb": DebugConfigProvider<"lldb", CodeLldbDebugConfig>;
+    "ms-vscode.cpptools": DebugConfigProvider<"cppvsdbg" | "cppdbg", CCppDebugConfig>;
+    "webfreak.debug": DebugConfigProvider<"gdb", NativeDebugConfig>;
+} = {
+    "vadimcn.vscode-lldb": {
+        type: "lldb",
+        executableProperty: "program",
+        environmentProperty: (env) => ["env", env],
+        runnableArgsProperty: (runnableArgs: ra.CargoRunnableArgs) => [
+            "args",
+            runnableArgs.executableArgs,
+        ],
+        sourceFileMapProperty: "sourceMap",
+        additional: {
+            sourceLanguages: ["rust"],
+        },
+    },
+    "ms-vscode.cpptools": {
+        type: os.platform() === "win32" ? "cppvsdbg" : "cppdbg",
+        executableProperty: "program",
+        environmentProperty: (env) => [
+            "environment",
+            Object.entries(env).map((entry) => ({
+                name: entry[0],
+                value: entry[1],
+            })),
+        ],
+        runnableArgsProperty: (runnableArgs: ra.CargoRunnableArgs) => [
+            "args",
+            runnableArgs.executableArgs,
+        ],
+        sourceFileMapProperty: "sourceFileMap",
+        additional: {
+            osx: {
+                MIMode: "lldb",
+            },
+        },
+    },
+    "webfreak.debug": {
+        type: "gdb",
+        executableProperty: "target",
+        runnableArgsProperty: (runnableArgs: ra.CargoRunnableArgs) => [
+            "arguments",
+            quote(runnableArgs.executableArgs),
+        ],
+        environmentProperty: (env) => ["env", env],
+        additional: {
+            valuesFormatting: "prettyPrinters",
+        },
+    },
+};
+
 async function getDebugExecutable(
     runnableArgs: ra.CargoRunnableArgs,
     env: Record<string, string>,
@@ -197,71 +276,74 @@ async function getDebugExecutable(
     return executable;
 }
 
-function getCCppDebugConfig(
-    runnable: ra.Runnable,
-    runnableArgs: ra.CargoRunnableArgs,
-    executable: string,
-    env: Record<string, string>,
-    sourceFileMap?: Record<string, string>,
-): vscode.DebugConfiguration {
-    return {
-        type: os.platform() === "win32" ? "cppvsdbg" : "cppdbg",
-        request: "launch",
-        name: runnable.label,
-        program: executable,
-        args: runnableArgs.executableArgs,
-        cwd: runnable.args.cwd || runnableArgs.workspaceRoot || ".",
-        sourceFileMap,
-        environment: Object.entries(env).map((entry) => ({
-            name: entry[0],
-            value: entry[1],
-        })),
-        // See https://github.com/rust-lang/rust-analyzer/issues/16901#issuecomment-2024486941
-        osx: {
-            MIMode: "lldb",
-        },
-    };
-}
+type BaseDebugConfig<type extends string> = {
+    type: type;
+    request: "launch";
+    name: string;
+    cwd: string;
+};
 
-function getCodeLldbDebugConfig(
+function getDebugConfig(
+    provider: KnownEnginesType,
+    simplifyPath: (p: string) => string,
     runnable: ra.Runnable,
     runnableArgs: ra.CargoRunnableArgs,
     executable: string,
     env: Record<string, string>,
     sourceFileMap?: Record<string, string>,
 ): vscode.DebugConfiguration {
+    const {
+        environmentProperty,
+        executableProperty,
+        runnableArgsProperty,
+        type,
+        additional,
+        sourceFileMapProperty,
+    } = provider;
+    const [envProperty, envValue] = environmentProperty(env);
+    const [argsProperty, argsValue] = runnableArgsProperty(runnableArgs);
     return {
-        type: "lldb",
+        type,
         request: "launch",
         name: runnable.label,
-        program: executable,
-        args: runnableArgs.executableArgs,
-        cwd: runnable.args.cwd || runnableArgs.workspaceRoot || ".",
-        sourceMap: sourceFileMap,
-        sourceLanguages: ["rust"],
-        env,
+        cwd: simplifyPath(runnable.args.cwd || runnableArgs.workspaceRoot || "."),
+        [executableProperty]: simplifyPath(executable),
+        [envProperty]: envValue,
+        [argsProperty]: argsValue,
+        ...(sourceFileMapProperty ? { [sourceFileMapProperty]: sourceFileMap } : {}),
+        ...additional,
     };
 }
 
-function getNativeDebugConfig(
-    runnable: ra.Runnable,
-    runnableArgs: ra.CargoRunnableArgs,
-    executable: string,
-    env: Record<string, string>,
-    _sourceFileMap?: Record<string, string>,
-): vscode.DebugConfiguration {
-    return {
-        type: "gdb",
-        request: "launch",
-        name: runnable.label,
-        target: executable,
-        // See https://github.com/WebFreak001/code-debug/issues/359
-        arguments: quote(runnableArgs.executableArgs),
-        cwd: runnable.args.cwd || runnableArgs.workspaceRoot || ".",
-        env,
-        valuesFormatting: "prettyPrinters",
+type CCppDebugConfig = {
+    program: string;
+    args: string[];
+    sourceFileMap: Record<string, string> | undefined;
+    environment: {
+        name: string;
+        value: string;
+    }[];
+    // See https://github.com/rust-lang/rust-analyzer/issues/16901#issuecomment-2024486941
+    osx: {
+        MIMode: "lldb";
     };
-}
+} & BaseDebugConfig<"cppvsdbg" | "cppdbg">;
+
+type CodeLldbDebugConfig = {
+    program: string;
+    args: string[];
+    sourceMap: Record<string, string> | undefined;
+    sourceLanguages: ["rust"];
+    env: Record<string, string>;
+} & BaseDebugConfig<"lldb">;
+
+type NativeDebugConfig = {
+    target: string;
+    // See https://github.com/WebFreak001/code-debug/issues/359
+    arguments: string;
+    env: Record<string, string>;
+    valuesFormatting: "prettyPrinters";
+} & BaseDebugConfig<"gdb">;
 
 // Based on https://github.com/ljharb/shell-quote/blob/main/quote.js
 function quote(xs: string[]) {
diff --git a/src/tools/rust-analyzer/editors/code/src/run.ts b/src/tools/rust-analyzer/editors/code/src/run.ts
index 7179eb37447..dd0da6b62c8 100644
--- a/src/tools/rust-analyzer/editors/code/src/run.ts
+++ b/src/tools/rust-analyzer/editors/code/src/run.ts
@@ -65,9 +65,14 @@ export class RunnableQuickPick implements vscode.QuickPickItem {
     }
 }
 
-export function prepareBaseEnv(base?: Record<string, string>): Record<string, string> {
+export function prepareBaseEnv(
+    inheritEnv: boolean,
+    base?: Record<string, string>,
+): Record<string, string> {
     const env: Record<string, string> = { RUST_BACKTRACE: "short" };
-    Object.assign(env, process.env);
+    if (inheritEnv) {
+        Object.assign(env, process.env);
+    }
     if (base) {
         Object.assign(env, base);
     }
@@ -75,11 +80,12 @@ export function prepareBaseEnv(base?: Record<string, string>): Record<string, st
 }
 
 export function prepareEnv(
+    inheritEnv: boolean,
     label: string,
     runnableArgs: ra.CargoRunnableArgs,
     runnableEnvCfg?: RunnableEnvCfg,
 ): Record<string, string> {
-    const env = prepareBaseEnv(runnableArgs.environment);
+    const env = prepareBaseEnv(inheritEnv, runnableArgs.environment);
     const platform = process.platform;
 
     const checkPlatform = (it: RunnableEnvCfgItem) => {
@@ -134,7 +140,7 @@ export async function createTaskFromRunnable(
         };
         options = {
             cwd: runnableArgs.workspaceRoot || ".",
-            env: prepareEnv(runnable.label, runnableArgs, config.runnablesExtraEnv),
+            env: prepareEnv(true, runnable.label, runnableArgs, config.runnablesExtraEnv),
         };
     } else {
         const runnableArgs = runnable.args;
@@ -145,7 +151,7 @@ export async function createTaskFromRunnable(
         };
         options = {
             cwd: runnableArgs.cwd,
-            env: prepareBaseEnv(),
+            env: prepareBaseEnv(true),
         };
     }
 
diff --git a/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts b/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts
index 81850e03f1c..f0a62a3cce2 100644
--- a/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts
+++ b/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts
@@ -19,7 +19,7 @@ function makeRunnable(label: string): ra.Runnable {
 function fakePrepareEnv(runnableName: string, config?: RunnableEnvCfg): Record<string, string> {
     const runnable = makeRunnable(runnableName);
     const runnableArgs = runnable.args as ra.CargoRunnableArgs;
-    return prepareEnv(runnable.label, runnableArgs, config);
+    return prepareEnv(false, runnable.label, runnableArgs, config);
 }
 
 export async function getTests(ctx: Context) {