aboutsummaryrefslogtreecommitdiff
path: root/editors/code
diff options
context:
space:
mode:
authorvsrs <[email protected]>2020-06-18 20:20:13 +0100
committervsrs <[email protected]>2020-06-24 08:53:49 +0100
commita43a9103bc9a8c1bf735d51c952bc3b9352a00c3 (patch)
treeab29bcaca605deb29328789e627d1100c5a9517d /editors/code
parentc544f9a137bd675fd6e9cc4c244ff4366ededb50 (diff)
Add custom cargo runners
Diffstat (limited to 'editors/code')
-rw-r--r--editors/code/package.json8
-rw-r--r--editors/code/src/commands.ts4
-rw-r--r--editors/code/src/config.ts4
-rw-r--r--editors/code/src/main.ts2
-rw-r--r--editors/code/src/run.ts57
-rw-r--r--editors/code/src/tasks.ts54
6 files changed, 73 insertions, 56 deletions
diff --git a/editors/code/package.json b/editors/code/package.json
index 68484a370..f542a490a 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -336,6 +336,14 @@
336 "default": null, 336 "default": null,
337 "description": "List of features to activate. Defaults to `rust-analyzer.cargo.features`." 337 "description": "List of features to activate. Defaults to `rust-analyzer.cargo.features`."
338 }, 338 },
339 "rust-analyzer.cargoRunner": {
340 "type": [
341 "null",
342 "string"
343 ],
344 "default": null,
345 "description": "Custom cargo runner extension ID."
346 },
339 "rust-analyzer.inlayHints.enable": { 347 "rust-analyzer.inlayHints.enable": {
340 "type": "boolean", 348 "type": "boolean",
341 "default": true, 349 "default": true,
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index 48a25495f..8c9d7802f 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -394,7 +394,7 @@ export function run(ctx: Ctx): Cmd {
394 394
395 item.detail = 'rerun'; 395 item.detail = 'rerun';
396 prevRunnable = item; 396 prevRunnable = item;
397 const task = createTask(item.runnable); 397 const task = await createTask(item.runnable, ctx.config);
398 return await vscode.tasks.executeTask(task); 398 return await vscode.tasks.executeTask(task);
399 }; 399 };
400} 400}
@@ -404,7 +404,7 @@ export function runSingle(ctx: Ctx): Cmd {
404 const editor = ctx.activeRustEditor; 404 const editor = ctx.activeRustEditor;
405 if (!editor) return; 405 if (!editor) return;
406 406
407 const task = createTask(runnable); 407 const task = await createTask(runnable, ctx.config);
408 task.group = vscode.TaskGroup.Build; 408 task.group = vscode.TaskGroup.Build;
409 task.presentationOptions = { 409 task.presentationOptions = {
410 reveal: vscode.TaskRevealKind.Always, 410 reveal: vscode.TaskRevealKind.Always,
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index 9591d4fe3..fc95a7de6 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -110,6 +110,10 @@ export class Config {
110 }; 110 };
111 } 111 }
112 112
113 get cargoRunner() {
114 return this.get<string | undefined>("cargoRunner");
115 }
116
113 get debug() { 117 get debug() {
114 // "/rustc/<id>" used by suggestions only. 118 // "/rustc/<id>" used by suggestions only.
115 const { ["/rustc/<id>"]: _, ...sourceFileMap } = this.get<Record<string, string>>("debug.sourceFileMap"); 119 const { ["/rustc/<id>"]: _, ...sourceFileMap } = this.get<Record<string, string>>("debug.sourceFileMap");
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 12b4d0510..5b4f453c8 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -115,7 +115,7 @@ export async function activate(context: vscode.ExtensionContext) {
115 ctx.registerCommand('applyActionGroup', commands.applyActionGroup); 115 ctx.registerCommand('applyActionGroup', commands.applyActionGroup);
116 ctx.registerCommand('gotoLocation', commands.gotoLocation); 116 ctx.registerCommand('gotoLocation', commands.gotoLocation);
117 117
118 ctx.pushCleanup(activateTaskProvider(workspaceFolder)); 118 ctx.pushCleanup(activateTaskProvider(workspaceFolder, ctx.config));
119 119
120 activateStatusDisplay(ctx); 120 activateStatusDisplay(ctx);
121 121
diff --git a/editors/code/src/run.ts b/editors/code/src/run.ts
index bb060cfe1..7ecdeeeaf 100644
--- a/editors/code/src/run.ts
+++ b/editors/code/src/run.ts
@@ -1,10 +1,11 @@
1import * as vscode from 'vscode'; 1import * as vscode from 'vscode';
2import * as lc from 'vscode-languageclient'; 2import * as lc from 'vscode-languageclient';
3import * as ra from './lsp_ext'; 3import * as ra from './lsp_ext';
4import * as toolchain from "./toolchain"; 4import * as tasks from './tasks';
5 5
6import { Ctx } from './ctx'; 6import { Ctx } from './ctx';
7import { makeDebugConfig } from './debug'; 7import { makeDebugConfig } from './debug';
8import { Config } from './config';
8 9
9const quickPickButtons = [{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configurtation." }]; 10const quickPickButtons = [{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configurtation." }];
10 11
@@ -95,52 +96,28 @@ export class RunnableQuickPick implements vscode.QuickPickItem {
95 } 96 }
96} 97}
97 98
98interface CargoTaskDefinition extends vscode.TaskDefinition { 99export async function createTask(runnable: ra.Runnable, config: Config): Promise<vscode.Task> {
99 type: 'cargo'; 100 if (runnable.kind !== "cargo") {
100 label: string; 101 // rust-analyzer supports only one kind, "cargo"
101 command: string; 102 // do not use tasks.TASK_TYPE here, these are completely different meanings.
102 args: string[];
103 env?: { [key: string]: string };
104}
105
106export function createTask(runnable: ra.Runnable): vscode.Task {
107 const TASK_SOURCE = 'Rust';
108 103
109 let command; 104 throw `Unexpected runnable kind: ${runnable.kind}`;
110 switch (runnable.kind) {
111 case "cargo": command = toolchain.getPathForExecutable("cargo");
112 } 105 }
106
113 const args = [...runnable.args.cargoArgs]; // should be a copy! 107 const args = [...runnable.args.cargoArgs]; // should be a copy!
114 if (runnable.args.executableArgs.length > 0) { 108 if (runnable.args.executableArgs.length > 0) {
115 args.push('--', ...runnable.args.executableArgs); 109 args.push('--', ...runnable.args.executableArgs);
116 } 110 }
117 const definition: CargoTaskDefinition = { 111 const definition: tasks.CargoTaskDefinition = {
118 type: 'cargo', 112 type: tasks.TASK_TYPE,
119 label: runnable.label, 113 command: args[0], // run, test, etc...
120 command, 114 args: args.slice(1),
121 args, 115 cwd: runnable.args.workspaceRoot,
122 env: Object.assign({}, process.env as { [key: string]: string }, { "RUST_BACKTRACE": "short" }), 116 env: Object.assign({}, process.env as { [key: string]: string }, { "RUST_BACKTRACE": "short" }),
123 }; 117 };
124 118
125 const execOption: vscode.ShellExecutionOptions = { 119 const cargoTask = await tasks.buildCargoTask(definition, runnable.label, args, config.cargoRunner);
126 cwd: runnable.args.workspaceRoot || '.', 120 cargoTask.presentationOptions.clear = true;
127 env: definition.env, 121
128 }; 122 return cargoTask;
129 const exec = new vscode.ShellExecution(
130 definition.command,
131 definition.args,
132 execOption,
133 );
134
135 const f = vscode.workspace.workspaceFolders![0];
136 const t = new vscode.Task(
137 definition,
138 f,
139 definition.label,
140 TASK_SOURCE,
141 exec,
142 ['$rustc'],
143 );
144 t.presentationOptions.clear = true;
145 return t;
146} 123}
diff --git a/editors/code/src/tasks.ts b/editors/code/src/tasks.ts
index 9748824df..e2c43fdd4 100644
--- a/editors/code/src/tasks.ts
+++ b/editors/code/src/tasks.ts
@@ -1,11 +1,14 @@
1import * as vscode from 'vscode'; 1import * as vscode from 'vscode';
2import * as toolchain from "./toolchain"; 2import * as toolchain from "./toolchain";
3import { Config } from './config';
4import { log } from './util';
3 5
4// This ends up as the `type` key in tasks.json. RLS also uses `cargo` and 6// This ends up as the `type` key in tasks.json. RLS also uses `cargo` and
5// our configuration should be compatible with it so use the same key. 7// our configuration should be compatible with it so use the same key.
6const TASK_TYPE = 'cargo'; 8export const TASK_TYPE = 'cargo';
9export const TASK_SOURCE = 'rust';
7 10
8interface CargoTaskDefinition extends vscode.TaskDefinition { 11export interface CargoTaskDefinition extends vscode.TaskDefinition {
9 command?: string; 12 command?: string;
10 args?: string[]; 13 args?: string[];
11 cwd?: string; 14 cwd?: string;
@@ -14,9 +17,11 @@ interface CargoTaskDefinition extends vscode.TaskDefinition {
14 17
15class CargoTaskProvider implements vscode.TaskProvider { 18class CargoTaskProvider implements vscode.TaskProvider {
16 private readonly target: vscode.WorkspaceFolder; 19 private readonly target: vscode.WorkspaceFolder;
20 private readonly config: Config;
17 21
18 constructor(target: vscode.WorkspaceFolder) { 22 constructor(target: vscode.WorkspaceFolder, config: Config) {
19 this.target = target; 23 this.target = target;
24 this.config = config;
20 } 25 }
21 26
22 provideTasks(): vscode.Task[] { 27 provideTasks(): vscode.Task[] {
@@ -58,29 +63,52 @@ class CargoTaskProvider implements vscode.TaskProvider {
58 }); 63 });
59 } 64 }
60 65
61 resolveTask(task: vscode.Task): vscode.Task | undefined { 66 async resolveTask(task: vscode.Task): Promise<vscode.Task | undefined> {
62 // VSCode calls this for every cargo task in the user's tasks.json, 67 // VSCode calls this for every cargo task in the user's tasks.json,
63 // we need to inform VSCode how to execute that command by creating 68 // we need to inform VSCode how to execute that command by creating
64 // a ShellExecution for it. 69 // a ShellExecution for it.
65 70
66 const definition = task.definition as CargoTaskDefinition; 71 const definition = task.definition as CargoTaskDefinition;
67 72
68 if (definition.type === 'cargo' && definition.command) { 73 if (definition.type === TASK_TYPE && definition.command) {
69 const args = [definition.command].concat(definition.args ?? []); 74 const args = [definition.command].concat(definition.args ?? []);
70 75
71 return new vscode.Task( 76 return await buildCargoTask(definition, task.name, args, this.config.cargoRunner);
72 definition,
73 task.name,
74 'rust',
75 new vscode.ShellExecution('cargo', args, definition),
76 );
77 } 77 }
78 78
79 return undefined; 79 return undefined;
80 } 80 }
81} 81}
82 82
83export function activateTaskProvider(target: vscode.WorkspaceFolder): vscode.Disposable { 83export async function buildCargoTask(definition: CargoTaskDefinition, name: string, args: string[], customRunner?: string): Promise<vscode.Task> {
84 const provider = new CargoTaskProvider(target); 84 if (customRunner) {
85 const runnerCommand = `${customRunner}.createCargoTask`;
86 try {
87 const runnerArgs = { name, args, cwd: definition.cwd, env: definition.env, source: TASK_SOURCE };
88 const task = await vscode.commands.executeCommand(runnerCommand, runnerArgs);
89
90 if (task instanceof vscode.Task) {
91 return task;
92 } else if (task) {
93 log.debug("Invalid cargo task", task);
94 throw `Invalid task!`;
95 }
96 // fallback to default processing
97
98 } catch (e) {
99 throw `Cargo runner '${customRunner}' failed! ${e}`;
100 }
101 }
102
103 return new vscode.Task(
104 definition,
105 name,
106 TASK_SOURCE,
107 new vscode.ShellExecution(toolchain.cargoPath(), args, definition),
108 );
109}
110
111export function activateTaskProvider(target: vscode.WorkspaceFolder, config: Config): vscode.Disposable {
112 const provider = new CargoTaskProvider(target, config);
85 return vscode.tasks.registerTaskProvider(TASK_TYPE, provider); 113 return vscode.tasks.registerTaskProvider(TASK_TYPE, provider);
86} 114}