diff options
author | vsrs <[email protected]> | 2020-06-18 20:20:13 +0100 |
---|---|---|
committer | vsrs <[email protected]> | 2020-06-24 08:53:49 +0100 |
commit | a43a9103bc9a8c1bf735d51c952bc3b9352a00c3 (patch) | |
tree | ab29bcaca605deb29328789e627d1100c5a9517d /editors/code | |
parent | c544f9a137bd675fd6e9cc4c244ff4366ededb50 (diff) |
Add custom cargo runners
Diffstat (limited to 'editors/code')
-rw-r--r-- | editors/code/package.json | 8 | ||||
-rw-r--r-- | editors/code/src/commands.ts | 4 | ||||
-rw-r--r-- | editors/code/src/config.ts | 4 | ||||
-rw-r--r-- | editors/code/src/main.ts | 2 | ||||
-rw-r--r-- | editors/code/src/run.ts | 57 | ||||
-rw-r--r-- | editors/code/src/tasks.ts | 54 |
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 @@ | |||
1 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | import * as lc from 'vscode-languageclient'; | 2 | import * as lc from 'vscode-languageclient'; |
3 | import * as ra from './lsp_ext'; | 3 | import * as ra from './lsp_ext'; |
4 | import * as toolchain from "./toolchain"; | 4 | import * as tasks from './tasks'; |
5 | 5 | ||
6 | import { Ctx } from './ctx'; | 6 | import { Ctx } from './ctx'; |
7 | import { makeDebugConfig } from './debug'; | 7 | import { makeDebugConfig } from './debug'; |
8 | import { Config } from './config'; | ||
8 | 9 | ||
9 | const quickPickButtons = [{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configurtation." }]; | 10 | const 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 | ||
98 | interface CargoTaskDefinition extends vscode.TaskDefinition { | 99 | export 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 | |||
106 | export 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 @@ | |||
1 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | import * as toolchain from "./toolchain"; | 2 | import * as toolchain from "./toolchain"; |
3 | import { Config } from './config'; | ||
4 | import { 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. |
6 | const TASK_TYPE = 'cargo'; | 8 | export const TASK_TYPE = 'cargo'; |
9 | export const TASK_SOURCE = 'rust'; | ||
7 | 10 | ||
8 | interface CargoTaskDefinition extends vscode.TaskDefinition { | 11 | export 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 | ||
15 | class CargoTaskProvider implements vscode.TaskProvider { | 18 | class 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 | ||
83 | export function activateTaskProvider(target: vscode.WorkspaceFolder): vscode.Disposable { | 83 | export 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 | |||
111 | export 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 | } |