about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-03-18 08:48:57 +0000
committerbors <bors@rust-lang.org>2024-03-18 08:48:57 +0000
commitf6e2895ee667b0c65b022d67dee6287be65edf37 (patch)
tree193d5cfc66a508f269e9bd8ccb962887c8c02174
parenta71a0328d8819590edb636426cacc1f847f13adc (diff)
parent4422a90b1106065146d0f3f6d0aa86c212753c10 (diff)
downloadrust-f6e2895ee667b0c65b022d67dee6287be65edf37.tar.gz
rust-f6e2895ee667b0c65b022d67dee6287be65edf37.zip
Auto merge of #16839 - Wilfred:extension_refactor_for_shell, r=Veykril
Refactor extension to support arbitrary shell command runnables

Currently, the extension assumes that all runnables invoke cargo. Arguments are sometimes full CLI arguments, and sometimes arguments passed to a cargo subcommand.

Refactor the extension so that tasks are just a `program` and a list of strings `args`, and rename `CargoTask` to `RustTask` to make it generic.

(This was factored out of #16135 and tidied.)
-rw-r--r--editors/code/src/run.ts28
-rw-r--r--editors/code/src/tasks.ts50
2 files changed, 40 insertions, 38 deletions
diff --git a/editors/code/src/run.ts b/editors/code/src/run.ts
index fc3f1acce54..02ccbb6956a 100644
--- a/editors/code/src/run.ts
+++ b/editors/code/src/run.ts
@@ -2,6 +2,7 @@ import * as vscode from "vscode";
 import type * as lc from "vscode-languageclient";
 import * as ra from "./lsp_ext";
 import * as tasks from "./tasks";
+import * as toolchain from "./toolchain";
 
 import type { CtxInit } from "./ctx";
 import { makeDebugConfig } from "./debug";
@@ -111,12 +112,22 @@ export async function createTask(runnable: ra.Runnable, config: Config): Promise
         throw `Unexpected runnable kind: ${runnable.kind}`;
     }
 
-    const args = createArgs(runnable);
+    let program: string;
+    let args = createArgs(runnable);
+    if (runnable.args.overrideCargo) {
+        // Split on spaces to allow overrides like "wrapper cargo".
+        const cargoParts = runnable.args.overrideCargo.split(" ");
 
-    const definition: tasks.CargoTaskDefinition = {
+        program = unwrapUndefinable(cargoParts[0]);
+        args = [...cargoParts.slice(1), ...args];
+    } else {
+        program = await toolchain.cargoPath();
+    }
+
+    const definition: tasks.RustTargetDefinition = {
         type: tasks.TASK_TYPE,
-        command: args[0], // run, test, etc...
-        args: args.slice(1),
+        program,
+        args,
         cwd: runnable.args.workspaceRoot || ".",
         env: prepareEnv(runnable, config.runnablesExtraEnv),
         overrideCargo: runnable.args.overrideCargo,
@@ -124,22 +135,21 @@ export async function createTask(runnable: ra.Runnable, config: Config): Promise
 
     // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
     const target = vscode.workspace.workspaceFolders![0]; // safe, see main activate()
-    const cargoTask = await tasks.buildCargoTask(
+    const task = await tasks.buildRustTask(
         target,
         definition,
         runnable.label,
-        args,
         config.problemMatcher,
         config.cargoRunner,
         true,
     );
 
-    cargoTask.presentationOptions.clear = true;
+    task.presentationOptions.clear = true;
     // Sadly, this doesn't prevent focus stealing if the terminal is currently
     // hidden, and will become revealed due to task execution.
-    cargoTask.presentationOptions.focus = false;
+    task.presentationOptions.focus = false;
 
-    return cargoTask;
+    return task;
 }
 
 export function createArgs(runnable: ra.Runnable): string[] {
diff --git a/editors/code/src/tasks.ts b/editors/code/src/tasks.ts
index 1d5ab82aa04..89abb37b0eb 100644
--- a/editors/code/src/tasks.ts
+++ b/editors/code/src/tasks.ts
@@ -2,22 +2,20 @@ import * as vscode from "vscode";
 import * as toolchain from "./toolchain";
 import type { Config } from "./config";
 import { log } from "./util";
-import { unwrapUndefinable } from "./undefinable";
 
 // 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.
 export const TASK_TYPE = "cargo";
 export const TASK_SOURCE = "rust";
 
-export interface CargoTaskDefinition extends vscode.TaskDefinition {
-    command?: string;
-    args?: string[];
+export interface RustTargetDefinition extends vscode.TaskDefinition {
+    program: string;
+    args: string[];
     cwd?: string;
     env?: { [key: string]: string };
-    overrideCargo?: string;
 }
 
-class CargoTaskProvider implements vscode.TaskProvider {
+class RustTaskProvider implements vscode.TaskProvider {
     private readonly config: Config;
 
     constructor(config: Config) {
@@ -39,14 +37,15 @@ class CargoTaskProvider implements vscode.TaskProvider {
             { command: "run", group: undefined },
         ];
 
+        const cargoPath = await toolchain.cargoPath();
+
         const tasks: vscode.Task[] = [];
         for (const workspaceTarget of vscode.workspace.workspaceFolders || []) {
             for (const def of defs) {
-                const vscodeTask = await buildCargoTask(
+                const vscodeTask = await buildRustTask(
                     workspaceTarget,
-                    { type: TASK_TYPE, command: def.command },
+                    { type: TASK_TYPE, program: cargoPath, args: [def.command] },
                     `cargo ${def.command}`,
-                    [def.command],
                     this.config.problemMatcher,
                     this.config.cargoRunner,
                 );
@@ -63,15 +62,13 @@ class CargoTaskProvider implements vscode.TaskProvider {
         // we need to inform VSCode how to execute that command by creating
         // a ShellExecution for it.
 
-        const definition = task.definition as CargoTaskDefinition;
+        const definition = task.definition as RustTargetDefinition;
 
-        if (definition.type === TASK_TYPE && definition.command) {
-            const args = [definition.command].concat(definition.args ?? []);
-            return await buildCargoTask(
+        if (definition.type === TASK_TYPE) {
+            return await buildRustTask(
                 task.scope,
                 definition,
                 task.name,
-                args,
                 this.config.problemMatcher,
                 this.config.cargoRunner,
             );
@@ -81,11 +78,10 @@ class CargoTaskProvider implements vscode.TaskProvider {
     }
 }
 
-export async function buildCargoTask(
+export async function buildRustTask(
     scope: vscode.WorkspaceFolder | vscode.TaskScope | undefined,
-    definition: CargoTaskDefinition,
+    definition: RustTargetDefinition,
     name: string,
-    args: string[],
     problemMatcher: string[],
     customRunner?: string,
     throwOnError: boolean = false,
@@ -95,7 +91,12 @@ export async function buildCargoTask(
     if (customRunner) {
         const runnerCommand = `${customRunner}.buildShellExecution`;
         try {
-            const runnerArgs = { kind: TASK_TYPE, args, cwd: definition.cwd, env: definition.env };
+            const runnerArgs = {
+                kind: TASK_TYPE,
+                args: definition.args,
+                cwd: definition.cwd,
+                env: definition.env,
+            };
             const customExec = await vscode.commands.executeCommand(runnerCommand, runnerArgs);
             if (customExec) {
                 if (customExec instanceof vscode.ShellExecution) {
@@ -113,16 +114,7 @@ export async function buildCargoTask(
     }
 
     if (!exec) {
-        // Check whether we must use a user-defined substitute for cargo.
-        // Split on spaces to allow overrides like "wrapper cargo".
-        const overrideCargo = definition.overrideCargo ?? definition.overrideCargo;
-        const cargoPath = await toolchain.cargoPath();
-        const cargoCommand = overrideCargo?.split(" ") ?? [cargoPath];
-
-        const fullCommand = [...cargoCommand, ...args];
-
-        const processName = unwrapUndefinable(fullCommand[0]);
-        exec = new vscode.ProcessExecution(processName, fullCommand.slice(1), definition);
+        exec = new vscode.ProcessExecution(definition.program, definition.args, definition);
     }
 
     return new vscode.Task(
@@ -138,6 +130,6 @@ export async function buildCargoTask(
 }
 
 export function activateTaskProvider(config: Config): vscode.Disposable {
-    const provider = new CargoTaskProvider(config);
+    const provider = new RustTaskProvider(config);
     return vscode.tasks.registerTaskProvider(TASK_TYPE, provider);
 }