diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index d2dc740c09..cadab37f51 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -8,10 +8,9 @@ import type { Disposable } from "vscode"; export type RunnableEnvCfgItem = { mask?: string; - env: Record; + env: { [key: string]: { toString(): string } | null }; platform?: string | string[]; }; -export type RunnableEnvCfg = Record | RunnableEnvCfgItem[]; type ShowStatusBar = "always" | "never" | { documentSelector: vscode.DocumentSelector }; @@ -261,18 +260,9 @@ export class Config { return this.get("testExplorer"); } - runnablesExtraEnv(label: string): Record | undefined { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const item = this.get("runnables.extraEnv") ?? this.get("runnableEnv"); - if (!item) return undefined; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const fixRecord = (r: Record) => { - for (const key in r) { - if (typeof r[key] !== "string") { - r[key] = String(r[key]); - } - } - }; + runnablesExtraEnv(label: string): Env { + let extraEnv = this.get("runnables.extraEnv") ?? {}; + if (!extraEnv) return {}; const platform = process.platform; const checkPlatform = (it: RunnableEnvCfgItem) => { @@ -283,19 +273,24 @@ export class Config { return true; }; - if (item instanceof Array) { + if (extraEnv instanceof Array) { const env = {}; - for (const it of item) { + for (const it of extraEnv) { const masked = !it.mask || new RegExp(it.mask).test(label); if (masked && checkPlatform(it)) { Object.assign(env, it.env); } } - fixRecord(env); - return env; + extraEnv = env; } - fixRecord(item); - return item; + return substituteVariablesInEnv( + Object.fromEntries( + Object.entries(extraEnv).map(([k, v]) => [ + k, + typeof v === "string" ? v : v?.toString(), + ]), + ), + ); } get restartServerOnConfigChange() { @@ -490,11 +485,11 @@ function computeVscodeVar(varName: string): string | null { folder === undefined ? "" // no workspace opened : // could use currently opened document to detect the correct - // workspace. However, that would be determined by the document - // user has opened on Editor startup. Could lead to - // unpredictable workspace selection in practice. - // It's better to pick the first one - normalizeDriveLetter(folder.uri.fsPath); + // workspace. However, that would be determined by the document + // user has opened on Editor startup. Could lead to + // unpredictable workspace selection in practice. + // It's better to pick the first one + normalizeDriveLetter(folder.uri.fsPath); return fsPath; }; // https://code.visualstudio.com/docs/editor/variables-reference diff --git a/editors/code/src/debug.ts b/editors/code/src/debug.ts index adb75c23c7..9559fe16f5 100644 --- a/editors/code/src/debug.ts +++ b/editors/code/src/debug.ts @@ -6,7 +6,7 @@ import type * as ra from "./lsp_ext"; import { Cargo } from "./toolchain"; import type { Ctx } from "./ctx"; import { createTaskFromRunnable, prepareEnv } from "./run"; -import { execute, isCargoRunnableArgs, unwrapUndefinable, log, normalizeDriveLetter } from "./util"; +import { execute, isCargoRunnableArgs, unwrapUndefinable, log, normalizeDriveLetter, Env } from "./util"; import type { Config } from "./config"; // Here we want to keep track on everything that's currently running @@ -108,9 +108,9 @@ async function getDebugConfiguration( await vscode.window.showErrorMessage( `Install [CodeLLDB](command:${commandCodeLLDB} "Open CodeLLDB")` + - `, [lldb-dap](command:${commandLLDBDap} "Open lldb-dap")` + - `, [C/C++](command:${commandCCpp} "Open C/C++") ` + - `or [Native Debug](command:${commandNativeDebug} "Open Native Debug") for debugging.`, + `, [lldb-dap](command:${commandLLDBDap} "Open lldb-dap")` + + `, [C/C++](command:${commandCCpp} "Open C/C++") ` + + `or [Native Debug](command:${commandNativeDebug} "Open Native Debug") for debugging.`, ); return; } @@ -124,7 +124,7 @@ async function getDebugConfiguration( !isMultiFolderWorkspace || !runnableArgs.workspaceRoot ? firstWorkspace : workspaceFolders.find((w) => runnableArgs.workspaceRoot?.includes(w.uri.fsPath)) || - firstWorkspace; + firstWorkspace; const workspace = unwrapUndefinable(maybeWorkspace); const wsFolder = normalizeDriveLetter(path.normalize(workspace.uri.fsPath)); @@ -207,7 +207,7 @@ type SourceFileMap = { }; async function discoverSourceFileMap( - env: Record, + env: Env, cwd: string, ): Promise { const sysroot = env["RUSTC_TOOLCHAIN"]; @@ -232,7 +232,7 @@ type PropertyFetcher = ( type DebugConfigProvider> = { executableProperty: keyof DebugConfig; - environmentProperty: PropertyFetcher, keyof DebugConfig>; + environmentProperty: PropertyFetcher; runnableArgsProperty: PropertyFetcher; sourceFileMapProperty?: keyof DebugConfig; type: Type; @@ -276,7 +276,7 @@ const knownEngines: { "environment", Object.entries(env).map((entry) => ({ name: entry[0], - value: entry[1], + value: entry[1] ?? "", })), ], runnableArgsProperty: (runnableArgs: ra.CargoRunnableArgs) => [ @@ -306,7 +306,7 @@ const knownEngines: { async function getDebugExecutable( runnableArgs: ra.CargoRunnableArgs, - env: Record, + env: Env, ): Promise { const cargo = new Cargo(runnableArgs.workspaceRoot || ".", env); const executable = await cargo.executableFromArgs(runnableArgs); @@ -328,7 +328,7 @@ function getDebugConfig( runnable: ra.Runnable, runnableArgs: ra.CargoRunnableArgs, executable: string, - env: Record, + env: Env, sourceFileMap?: Record, ): vscode.DebugConfiguration { const { @@ -380,14 +380,14 @@ type CodeLldbDebugConfig = { args: string[]; sourceMap: Record | undefined; sourceLanguages: ["rust"]; - env: Record; + env: Env; } & BaseDebugConfig<"lldb">; type NativeDebugConfig = { target: string; // See https://github.com/WebFreak001/code-debug/issues/359 arguments: string; - env: Record; + env: Env; valuesFormatting: "prettyPrinters"; } & BaseDebugConfig<"gdb">; diff --git a/editors/code/src/run.ts b/editors/code/src/run.ts index 95166c427b..bed874705d 100644 --- a/editors/code/src/run.ts +++ b/editors/code/src/run.ts @@ -7,7 +7,7 @@ import type { CtxInit } from "./ctx"; import { makeDebugConfig } from "./debug"; import type { Config } from "./config"; import type { LanguageClient } from "vscode-languageclient/node"; -import { log, unwrapUndefinable, type RustEditor } from "./util"; +import { Env, log, unwrapUndefinable, type RustEditor } from "./util"; const quickPickButtons = [ { iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configuration." }, @@ -124,9 +124,9 @@ export class RunnableQuickPick implements vscode.QuickPickItem { export function prepareBaseEnv( inheritEnv: boolean, - base?: Record, -): Record { - const env: Record = { RUST_BACKTRACE: "short" }; + base?: Env, +): Env { + const env: Env = { RUST_BACKTRACE: "short" }; if (inheritEnv) { Object.assign(env, process.env); } @@ -138,9 +138,9 @@ export function prepareBaseEnv( export function prepareEnv( inheritEnv: boolean, - runnableEnv?: Record, - runnableEnvCfg?: Record, -): Record { + runnableEnv?: Env, + runnableEnvCfg?: Env, +): Env { const env = prepareBaseEnv(inheritEnv, runnableEnv); if (runnableEnvCfg) { diff --git a/editors/code/src/tasks.ts b/editors/code/src/tasks.ts index 730ec6d1e9..417c28f0ee 100644 --- a/editors/code/src/tasks.ts +++ b/editors/code/src/tasks.ts @@ -1,6 +1,7 @@ import * as vscode from "vscode"; import type { Config } from "./config"; import * as toolchain from "./toolchain"; +import { Env } from "./util"; // This ends up as the `type` key in tasks.json. RLS also uses `cargo` and // our configuration should be compatible with it so use the same key. @@ -117,8 +118,8 @@ export async function buildRustTask( export async function targetToExecution( definition: TaskDefinition, options?: { - env?: { [key: string]: string }; cwd?: string; + env?: Env; }, cargo?: string, ): Promise { @@ -131,7 +132,14 @@ export async function targetToExecution( command = definition.command; args = definition.args || []; } - return new vscode.ProcessExecution(command, args, options); + return new vscode.ProcessExecution(command, args, { + cwd: options?.cwd, + env: + Object.fromEntries( + Object.entries(options?.env ?? {}).map(([key, value]) => [key, value ?? ""]) + ) + , + }); } export function activateTaskProvider(config: Config): vscode.Disposable { diff --git a/editors/code/src/toolchain.ts b/editors/code/src/toolchain.ts index a859ce6ff0..f64dec2ccf 100644 --- a/editors/code/src/toolchain.ts +++ b/editors/code/src/toolchain.ts @@ -3,7 +3,7 @@ import * as os from "os"; import * as path from "path"; import * as readline from "readline"; import * as vscode from "vscode"; -import { log, memoizeAsync, unwrapUndefinable } from "./util"; +import { Env, log, memoizeAsync, unwrapUndefinable } from "./util"; import type { CargoRunnableArgs } from "./lsp_ext"; interface CompilationArtifact { @@ -37,8 +37,8 @@ interface CompilerMessage { export class Cargo { constructor( readonly rootFolder: string, - readonly env: Record, - ) {} + readonly env: Env, + ) { } // Made public for testing purposes static artifactSpec(cargoArgs: string[], executableArgs?: string[]): ArtifactSpec { @@ -156,7 +156,7 @@ export class Cargo { /** Mirrors `toolchain::cargo()` implementation */ // FIXME: The server should provide this -export function cargoPath(env?: Record): Promise { +export function cargoPath(env?: Env): Promise { if (env?.["RUSTC_TOOLCHAIN"]) { return Promise.resolve("cargo"); }