aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_ide/src/runnables.rs35
-rw-r--r--crates/ra_proc_macro/src/process.rs2
-rw-r--r--crates/rust-analyzer/src/cargo_target_spec.rs5
-rw-r--r--crates/rust-analyzer/src/main_loop/handlers.rs2
-rw-r--r--crates/rust-analyzer/src/world.rs2
-rw-r--r--docs/user/readme.adoc20
-rw-r--r--editors/code/src/tasks.ts103
7 files changed, 127 insertions, 42 deletions
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs
index 9433f3a24..05a66e03c 100644
--- a/crates/ra_ide/src/runnables.rs
+++ b/crates/ra_ide/src/runnables.rs
@@ -34,7 +34,7 @@ impl Display for TestId {
34 34
35#[derive(Debug)] 35#[derive(Debug)]
36pub enum RunnableKind { 36pub enum RunnableKind {
37 Test { test_id: TestId }, 37 Test { test_id: TestId, attr: TestAttr },
38 TestMod { path: String }, 38 TestMod { path: String },
39 Bench { test_id: TestId }, 39 Bench { test_id: TestId },
40 Bin, 40 Bin,
@@ -77,7 +77,8 @@ fn runnable_fn(sema: &Semantics<RootDatabase>, fn_def: ast::FnDef) -> Option<Run
77 }; 77 };
78 78
79 if has_test_related_attribute(&fn_def) { 79 if has_test_related_attribute(&fn_def) {
80 RunnableKind::Test { test_id } 80 let attr = TestAttr::from_fn(&fn_def);
81 RunnableKind::Test { test_id, attr }
81 } else if fn_def.has_atom_attr("bench") { 82 } else if fn_def.has_atom_attr("bench") {
82 RunnableKind::Bench { test_id } 83 RunnableKind::Bench { test_id }
83 } else { 84 } else {
@@ -87,6 +88,21 @@ fn runnable_fn(sema: &Semantics<RootDatabase>, fn_def: ast::FnDef) -> Option<Run
87 Some(Runnable { range: fn_def.syntax().text_range(), kind }) 88 Some(Runnable { range: fn_def.syntax().text_range(), kind })
88} 89}
89 90
91#[derive(Debug)]
92pub struct TestAttr {
93 pub ignore: bool,
94}
95
96impl TestAttr {
97 fn from_fn(fn_def: &ast::FnDef) -> TestAttr {
98 let ignore = fn_def
99 .attrs()
100 .filter_map(|attr| attr.simple_name())
101 .any(|attribute_text| attribute_text == "ignore");
102 TestAttr { ignore }
103 }
104}
105
90/// This is a method with a heuristics to support test methods annotated with custom test annotations, such as 106/// This is a method with a heuristics to support test methods annotated with custom test annotations, such as
91/// `#[test_case(...)]`, `#[tokio::test]` and similar. 107/// `#[test_case(...)]`, `#[tokio::test]` and similar.
92/// Also a regular `#[test]` annotation is supported. 108/// Also a regular `#[test]` annotation is supported.
@@ -157,6 +173,9 @@ mod tests {
157 test_id: Path( 173 test_id: Path(
158 "test_foo", 174 "test_foo",
159 ), 175 ),
176 attr: TestAttr {
177 ignore: false,
178 },
160 }, 179 },
161 }, 180 },
162 Runnable { 181 Runnable {
@@ -165,6 +184,9 @@ mod tests {
165 test_id: Path( 184 test_id: Path(
166 "test_foo", 185 "test_foo",
167 ), 186 ),
187 attr: TestAttr {
188 ignore: true,
189 },
168 }, 190 },
169 }, 191 },
170 ] 192 ]
@@ -200,6 +222,9 @@ mod tests {
200 test_id: Path( 222 test_id: Path(
201 "test_mod::test_foo1", 223 "test_mod::test_foo1",
202 ), 224 ),
225 attr: TestAttr {
226 ignore: false,
227 },
203 }, 228 },
204 }, 229 },
205 ] 230 ]
@@ -237,6 +262,9 @@ mod tests {
237 test_id: Path( 262 test_id: Path(
238 "foo::test_mod::test_foo1", 263 "foo::test_mod::test_foo1",
239 ), 264 ),
265 attr: TestAttr {
266 ignore: false,
267 },
240 }, 268 },
241 }, 269 },
242 ] 270 ]
@@ -276,6 +304,9 @@ mod tests {
276 test_id: Path( 304 test_id: Path(
277 "foo::bar::test_mod::test_foo1", 305 "foo::bar::test_mod::test_foo1",
278 ), 306 ),
307 attr: TestAttr {
308 ignore: false,
309 },
279 }, 310 },
280 }, 311 },
281 ] 312 ]
diff --git a/crates/ra_proc_macro/src/process.rs b/crates/ra_proc_macro/src/process.rs
index 673f80a7a..5bcdacb48 100644
--- a/crates/ra_proc_macro/src/process.rs
+++ b/crates/ra_proc_macro/src/process.rs
@@ -189,7 +189,7 @@ fn mk_child(path: &Path, args: impl IntoIterator<Item = impl AsRef<OsStr>>) -> i
189 .args(args) 189 .args(args)
190 .stdin(Stdio::piped()) 190 .stdin(Stdio::piped())
191 .stdout(Stdio::piped()) 191 .stdout(Stdio::piped())
192 .stderr(Stdio::null()) 192 .stderr(Stdio::inherit())
193 .spawn() 193 .spawn()
194} 194}
195 195
diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs
index 942c30328..c2ece49f4 100644
--- a/crates/rust-analyzer/src/cargo_target_spec.rs
+++ b/crates/rust-analyzer/src/cargo_target_spec.rs
@@ -23,7 +23,7 @@ impl CargoTargetSpec {
23 let mut args = Vec::new(); 23 let mut args = Vec::new();
24 let mut extra_args = Vec::new(); 24 let mut extra_args = Vec::new();
25 match kind { 25 match kind {
26 RunnableKind::Test { test_id } => { 26 RunnableKind::Test { test_id, attr } => {
27 args.push("test".to_string()); 27 args.push("test".to_string());
28 if let Some(spec) = spec { 28 if let Some(spec) = spec {
29 spec.push_to(&mut args); 29 spec.push_to(&mut args);
@@ -33,6 +33,9 @@ impl CargoTargetSpec {
33 extra_args.push("--exact".to_string()); 33 extra_args.push("--exact".to_string());
34 } 34 }
35 extra_args.push("--nocapture".to_string()); 35 extra_args.push("--nocapture".to_string());
36 if attr.ignore {
37 extra_args.push("--ignored".to_string())
38 }
36 } 39 }
37 RunnableKind::TestMod { path } => { 40 RunnableKind::TestMod { path } => {
38 args.push("test".to_string()); 41 args.push("test".to_string());
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs
index b207f0764..41d9fe344 100644
--- a/crates/rust-analyzer/src/main_loop/handlers.rs
+++ b/crates/rust-analyzer/src/main_loop/handlers.rs
@@ -968,7 +968,7 @@ fn to_lsp_runnable(
968 let (args, extra_args) = CargoTargetSpec::runnable_args(spec, &runnable.kind)?; 968 let (args, extra_args) = CargoTargetSpec::runnable_args(spec, &runnable.kind)?;
969 let line_index = world.analysis().file_line_index(file_id)?; 969 let line_index = world.analysis().file_line_index(file_id)?;
970 let label = match &runnable.kind { 970 let label = match &runnable.kind {
971 RunnableKind::Test { test_id } => format!("test {}", test_id), 971 RunnableKind::Test { test_id, .. } => format!("test {}", test_id),
972 RunnableKind::TestMod { path } => format!("test-mod {}", path), 972 RunnableKind::TestMod { path } => format!("test-mod {}", path),
973 RunnableKind::Bench { test_id } => format!("bench {}", test_id), 973 RunnableKind::Bench { test_id } => format!("bench {}", test_id),
974 RunnableKind::Bin => "run binary".to_string(), 974 RunnableKind::Bin => "run binary".to_string(),
diff --git a/crates/rust-analyzer/src/world.rs b/crates/rust-analyzer/src/world.rs
index 8e1744bf9..7c0bb42aa 100644
--- a/crates/rust-analyzer/src/world.rs
+++ b/crates/rust-analyzer/src/world.rs
@@ -152,7 +152,7 @@ impl WorldState {
152 Ok(it) => it, 152 Ok(it) => it,
153 Err(err) => { 153 Err(err) => {
154 log::error!( 154 log::error!(
155 "Fail to run ra_proc_macro_srv from path {}, error: {:?}", 155 "Failed to run ra_proc_macro_srv from path {}, error: {:?}",
156 path, 156 path,
157 err 157 err
158 ); 158 );
diff --git a/docs/user/readme.adoc b/docs/user/readme.adoc
index 13ab2acc2..ce5704836 100644
--- a/docs/user/readme.adoc
+++ b/docs/user/readme.adoc
@@ -177,6 +177,26 @@ let g:LanguageClient_serverCommands = {
177\ } 177\ }
178---- 178----
179 179
180==== YouCompleteMe
181
1821. Install YouCompleteMe by following the instructions
183 https://ycm-core.github.io/YouCompleteMe/#rust-semantic-completion[here]
184
1852. Configure by adding this to your vim/neovim config file (replacing the existing Rust-specific line if it exists):
186+
187[source,vim]
188----
189let g:ycm_language_server =
190\ [
191\ {
192\ 'name': 'rust',
193\ 'cmdline': ['rust-analyzer'],
194\ 'filetypes': ['rust'],
195\ 'project_root_files': ['Cargo.toml']
196\ }
197\ ]
198----
199
180==== nvim-lsp 200==== nvim-lsp
181 201
182NeoVim 0.5 (not yet released) has built-in language server support. 202NeoVim 0.5 (not yet released) has built-in language server support.
diff --git a/editors/code/src/tasks.ts b/editors/code/src/tasks.ts
index fa1c4a951..1366c76d6 100644
--- a/editors/code/src/tasks.ts
+++ b/editors/code/src/tasks.ts
@@ -4,49 +4,80 @@ import * as vscode from 'vscode';
4// our configuration should be compatible with it so use the same key. 4// our configuration should be compatible with it so use the same key.
5const TASK_TYPE = 'cargo'; 5const TASK_TYPE = 'cargo';
6 6
7export function activateTaskProvider(target: vscode.WorkspaceFolder): vscode.Disposable { 7interface CargoTaskDefinition extends vscode.TaskDefinition {
8 const provider: vscode.TaskProvider = { 8 command?: string;
9 args?: string[];
10 cwd?: string;
11 env?: { [key: string]: string };
12}
13
14class CargoTaskProvider implements vscode.TaskProvider {
15 private readonly target: vscode.WorkspaceFolder;
16
17 constructor(target: vscode.WorkspaceFolder) {
18 this.target = target;
19 }
20
21 provideTasks(): vscode.Task[] {
9 // Detect Rust tasks. Currently we do not do any actual detection 22 // 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 23 // 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 24 // set of tasks that always exist. These tasks cannot be removed in
12 // tasks.json - only tweaked. 25 // tasks.json - only tweaked.
13 provideTasks: () => getStandardCargoTasks(target),
14 26
15 // We don't need to implement this. 27 return [
16 resolveTask: () => undefined, 28 { command: 'build', group: vscode.TaskGroup.Build },
17 }; 29 { command: 'check', group: vscode.TaskGroup.Build },
30 { command: 'test', group: vscode.TaskGroup.Test },
31 { command: 'clean', group: vscode.TaskGroup.Clean },
32 { command: 'run', group: undefined },
33 ]
34 .map(({ command, group }) => {
35 const vscodeTask = new vscode.Task(
36 // The contents of this object end up in the tasks.json entries.
37 {
38 type: TASK_TYPE,
39 command,
40 },
41 // The scope of the task - workspace or specific folder (global
42 // is not supported).
43 this.target,
44 // The task name, and task source. These are shown in the UI as
45 // `${source}: ${name}`, e.g. `rust: cargo build`.
46 `cargo ${command}`,
47 'rust',
48 // What to do when this command is executed.
49 new vscode.ShellExecution('cargo', [command]),
50 // Problem matchers.
51 ['$rustc'],
52 );
53 vscodeTask.group = group;
54 return vscodeTask;
55 });
56 }
18 57
19 return vscode.tasks.registerTaskProvider(TASK_TYPE, provider); 58 resolveTask(task: vscode.Task): vscode.Task | undefined {
20} 59 // VSCode calls this for every cargo task in the user's tasks.json,
60 // we need to inform VSCode how to execute that command by creating
61 // a ShellExecution for it.
21 62
22function getStandardCargoTasks(target: vscode.WorkspaceFolder): vscode.Task[] { 63 const definition = task.definition as CargoTaskDefinition;
23 return [ 64
24 { command: 'build', group: vscode.TaskGroup.Build }, 65 if (definition.type === 'cargo' && definition.command) {
25 { command: 'check', group: vscode.TaskGroup.Build }, 66 const args = [definition.command].concat(definition.args ?? []);
26 { command: 'test', group: vscode.TaskGroup.Test }, 67
27 { command: 'clean', group: vscode.TaskGroup.Clean }, 68 return new vscode.Task(
28 { command: 'run', group: undefined }, 69 definition,
29 ] 70 task.name,
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', 71 'rust',
44 // What to do when this command is executed. 72 new vscode.ShellExecution('cargo', args, definition),
45 new vscode.ShellExecution('cargo', [command]),
46 // Problem matchers.
47 ['$rustc'],
48 ); 73 );
49 vscodeTask.group = group; 74 }
50 return vscodeTask; 75
51 }); 76 return undefined;
77 }
52} 78}
79
80export function activateTaskProvider(target: vscode.WorkspaceFolder): vscode.Disposable {
81 const provider = new CargoTaskProvider(target);
82 return vscode.tasks.registerTaskProvider(TASK_TYPE, provider);
83} \ No newline at end of file