Skip to content

Commit 668980d

Browse files
bors[bot]Timmmmmatklad
authored
Merge #3777 #3784
3777: Add basic task support r=matklad a=Timmmm This adds basic support for running `cargo build`, `cargo run`, etc. Fixes #1935 I have tested this and it seems to work. There are two things I'm not sure about: 1. The workspace folder handling seems wrong - just get the first workspace folder? Is this just a TODO item? I don't know if it is right to lift `workspaceFolder` up to `activate()` but I couldn't see another way. 2. If you manually add an entry to `tasks.json` like this: ``` { "type": "cargo", "command": "build", "problemMatcher": [ "$rustc" ], "group": "build" } ``` then VSCode somehow magically knows to run `cargo build`. The documentation for `resolveTask` *sounds* like I should have to implement that for it to work: ``` * Resolves a task that has no [`execution`](#Task.execution) set. Tasks are * often created from information found in the `tasks.json`-file. Such tasks miss * the information on how to execute them and a task provider must fill in * the missing information in the `resolveTask`-method. ``` But then it also says this: ``` * This method will not be * called for tasks returned from the above `provideTasks` method since those * tasks are always fully resolved. A valid default implementation for the * `resolveTask` method is to return `undefined`. ``` Either way, it works without implementing it so the only thing I can think is that it is doing some kind of crazy pattern matching of the tasks returned by `provideTasks()` and the ones found in `tasks.json`. 3784: Ignore createProgress request in tests r=matklad a=matklad closes #3783 bors r+ 🤖 Co-authored-by: Tim <[email protected]> Co-authored-by: Aleksey Kladov <[email protected]>
3 parents 6f0d8db + 3eb45b9 + 6b2f02f commit 668980d

File tree

6 files changed

+80
-13
lines changed

6 files changed

+80
-13
lines changed

crates/rust-analyzer/src/main_loop.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -808,14 +808,14 @@ fn send_startup_progress(sender: &Sender<Message>, loop_state: &mut LoopState) {
808808
),
809809
_ => {}
810810
}
811-
}
812811

813-
fn send_startup_progress_notif(sender: &Sender<Message>, work_done_progress: WorkDoneProgress) {
814-
let notif = notification_new::<req::Progress>(req::ProgressParams {
815-
token: req::ProgressToken::String("rustAnalyzer/startup".into()),
816-
value: req::ProgressParamsValue::WorkDone(work_done_progress),
817-
});
818-
sender.send(notif.into()).unwrap();
812+
fn send_startup_progress_notif(sender: &Sender<Message>, work_done_progress: WorkDoneProgress) {
813+
let notif = notification_new::<req::Progress>(req::ProgressParams {
814+
token: req::ProgressToken::String("rustAnalyzer/startup".into()),
815+
value: req::ProgressParamsValue::WorkDone(work_done_progress),
816+
});
817+
sender.send(notif.into()).unwrap();
818+
}
819819
}
820820

821821
struct PoolDispatcher<'a> {

crates/rust-analyzer/tests/heavy_tests/support.rs

+1
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ impl Server {
188188
self.client.sender.send(r.into()).unwrap();
189189
while let Some(msg) = self.recv() {
190190
match msg {
191+
Message::Request(req) if req.method == "window/workDoneProgress/create" => (),
191192
Message::Request(req) => panic!("unexpected request: {:?}", req),
192193
Message::Notification(_) => (),
193194
Message::Response(res) => {

editors/code/src/client.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,14 @@ export function configToServerOptions(config: Config) {
3030
};
3131
}
3232

33-
export async function createClient(config: Config, serverPath: string): Promise<lc.LanguageClient> {
33+
export async function createClient(config: Config, serverPath: string, cwd: string): Promise<lc.LanguageClient> {
3434
// '.' Is the fallback if no folder is open
3535
// TODO?: Workspace folders support Uri's (eg: file://test.txt).
3636
// It might be a good idea to test if the uri points to a file.
37-
const workspaceFolderPath = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? '.';
3837

3938
const run: lc.Executable = {
4039
command: serverPath,
41-
options: { cwd: workspaceFolderPath },
40+
options: { cwd },
4241
};
4342
const serverOptions: lc.ServerOptions = {
4443
run,

editors/code/src/ctx.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,13 @@ export class Ctx {
1515

1616
}
1717

18-
static async create(config: Config, extCtx: vscode.ExtensionContext, serverPath: string): Promise<Ctx> {
19-
const client = await createClient(config, serverPath);
18+
static async create(
19+
config: Config,
20+
extCtx: vscode.ExtensionContext,
21+
serverPath: string,
22+
cwd: string,
23+
): Promise<Ctx> {
24+
const client = await createClient(config, serverPath, cwd);
2025
const res = new Ctx(config, extCtx, client, serverPath);
2126
res.pushCleanup(client.start());
2227
await client.onReady();

editors/code/src/main.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { log, assert } from './util';
1313
import { PersistentState } from './persistent_state';
1414
import { fetchRelease, download } from './net';
1515
import { spawnSync } from 'child_process';
16+
import { activateTaskProvider } from './tasks';
1617

1718
let ctx: Ctx | undefined;
1819

@@ -41,11 +42,18 @@ export async function activate(context: vscode.ExtensionContext) {
4142
const state = new PersistentState(context.globalState);
4243
const serverPath = await bootstrap(config, state);
4344

45+
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
46+
if (workspaceFolder === undefined) {
47+
const err = "Cannot activate rust-analyzer when no folder is opened";
48+
void vscode.window.showErrorMessage(err);
49+
throw new Error(err);
50+
}
51+
4452
// Note: we try to start the server before we activate type hints so that it
4553
// registers its `onDidChangeDocument` handler before us.
4654
//
4755
// This a horribly, horribly wrong way to deal with this problem.
48-
ctx = await Ctx.create(config, context, serverPath);
56+
ctx = await Ctx.create(config, context, serverPath, workspaceFolder.uri.fsPath);
4957

5058
// Commands which invokes manually via command palette, shortcut, etc.
5159

@@ -85,6 +93,8 @@ export async function activate(context: vscode.ExtensionContext) {
8593
ctx.registerCommand('applySourceChange', commands.applySourceChange);
8694
ctx.registerCommand('selectAndApplySourceChange', commands.selectAndApplySourceChange);
8795

96+
ctx.pushCleanup(activateTaskProvider(workspaceFolder));
97+
8898
activateStatusDisplay(ctx);
8999

90100
if (!ctx.config.highlightingSemanticTokens) {

editors/code/src/tasks.ts

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import * as vscode from 'vscode';
2+
3+
// This ends up as the `type` key in tasks.json. RLS also uses `cargo` and
4+
// our configuration should be compatible with it so use the same key.
5+
const TASK_TYPE = 'cargo';
6+
7+
export function activateTaskProvider(target: vscode.WorkspaceFolder): vscode.Disposable {
8+
const provider: vscode.TaskProvider = {
9+
// Detect Rust tasks. Currently we do not do any actual detection
10+
// of tasks (e.g. aliases in .cargo/config) and just return a fixed
11+
// set of tasks that always exist. These tasks cannot be removed in
12+
// tasks.json - only tweaked.
13+
provideTasks: () => getStandardCargoTasks(target),
14+
15+
// We don't need to implement this.
16+
resolveTask: () => undefined,
17+
};
18+
19+
return vscode.tasks.registerTaskProvider(TASK_TYPE, provider);
20+
}
21+
22+
function getStandardCargoTasks(target: vscode.WorkspaceFolder): vscode.Task[] {
23+
return [
24+
{ command: 'build', group: vscode.TaskGroup.Build },
25+
{ command: 'check', group: vscode.TaskGroup.Build },
26+
{ command: 'test', group: vscode.TaskGroup.Test },
27+
{ command: 'clean', group: vscode.TaskGroup.Clean },
28+
{ command: 'run', group: undefined },
29+
]
30+
.map(({ command, group }) => {
31+
const vscodeTask = new vscode.Task(
32+
// The contents of this object end up in the tasks.json entries.
33+
{
34+
type: TASK_TYPE,
35+
command,
36+
},
37+
// The scope of the task - workspace or specific folder (global
38+
// is not supported).
39+
target,
40+
// The task name, and task source. These are shown in the UI as
41+
// `${source}: ${name}`, e.g. `rust: cargo build`.
42+
`cargo ${command}`,
43+
'rust',
44+
// What to do when this command is executed.
45+
new vscode.ShellExecution('cargo', [command]),
46+
// Problem matchers.
47+
['$rustc'],
48+
);
49+
vscodeTask.group = group;
50+
return vscodeTask;
51+
});
52+
}

0 commit comments

Comments
 (0)