diff options
-rw-r--r-- | crates/ra_ide/src/runnables.rs | 35 | ||||
-rw-r--r-- | crates/ra_proc_macro/src/process.rs | 2 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cargo_target_spec.rs | 5 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop/handlers.rs | 2 | ||||
-rw-r--r-- | crates/rust-analyzer/src/world.rs | 2 | ||||
-rw-r--r-- | docs/user/readme.adoc | 20 | ||||
-rw-r--r-- | editors/code/src/tasks.ts | 103 |
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)] |
36 | pub enum RunnableKind { | 36 | pub 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)] | ||
92 | pub struct TestAttr { | ||
93 | pub ignore: bool, | ||
94 | } | ||
95 | |||
96 | impl 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 | |||
182 | 1. Install YouCompleteMe by following the instructions | ||
183 | https://ycm-core.github.io/YouCompleteMe/#rust-semantic-completion[here] | ||
184 | |||
185 | 2. Configure by adding this to your vim/neovim config file (replacing the existing Rust-specific line if it exists): | ||
186 | + | ||
187 | [source,vim] | ||
188 | ---- | ||
189 | let 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 | ||
182 | NeoVim 0.5 (not yet released) has built-in language server support. | 202 | NeoVim 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. |
5 | const TASK_TYPE = 'cargo'; | 5 | const TASK_TYPE = 'cargo'; |
6 | 6 | ||
7 | export function activateTaskProvider(target: vscode.WorkspaceFolder): vscode.Disposable { | 7 | interface 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 | |||
14 | class 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 | ||
22 | function 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 | |||
80 | export 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 | ||