diff options
author | Mikhail Rakhmanov <[email protected]> | 2020-06-02 22:22:45 +0100 |
---|---|---|
committer | Mikhail Rakhmanov <[email protected]> | 2020-06-02 22:22:45 +0100 |
commit | cb482e6351c4005f29bb89d38c64c4e3f93d7a6d (patch) | |
tree | c96d88e98c1a4fd59c37741e94faeefe465f4fb3 | |
parent | 57cd936c5262c3b43626618be42d7a72f71c3539 (diff) | |
parent | 2f6ab77708ae104c854712285af19516287b6906 (diff) |
Merge remote-tracking branch 'upstream/master' into compute-lazy-assits
# Conflicts:
# crates/rust-analyzer/src/to_proto.rs
-rw-r--r-- | crates/ra_ide/src/display/navigation_target.rs | 66 | ||||
-rw-r--r-- | crates/ra_ide/src/runnables.rs | 250 | ||||
-rw-r--r-- | crates/ra_project_model/src/cargo_workspace.rs | 2 | ||||
-rw-r--r-- | crates/rust-analyzer/src/caps.rs | 3 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cargo_target_spec.rs | 85 | ||||
-rw-r--r-- | crates/rust-analyzer/src/config.rs | 2 | ||||
-rw-r--r-- | crates/rust-analyzer/src/lsp_ext.rs | 31 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop/handlers.rs | 165 | ||||
-rw-r--r-- | crates/rust-analyzer/src/to_proto.rs | 38 | ||||
-rw-r--r-- | crates/rust-analyzer/tests/heavy_tests/main.rs | 113 | ||||
-rw-r--r-- | docs/dev/lsp-extensions.md | 80 | ||||
-rw-r--r-- | editors/code/package.json | 4 | ||||
-rw-r--r-- | editors/code/src/debug.ts | 12 | ||||
-rw-r--r-- | editors/code/src/lsp_ext.ts | 17 | ||||
-rw-r--r-- | editors/code/src/run.ts | 21 |
15 files changed, 546 insertions, 343 deletions
diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs index 5da28edd2..c7bb1e69f 100644 --- a/crates/ra_ide/src/display/navigation_target.rs +++ b/crates/ra_ide/src/display/navigation_target.rs | |||
@@ -92,15 +92,16 @@ impl NavigationTarget { | |||
92 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); | 92 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); |
93 | if let Some(src) = module.declaration_source(db) { | 93 | if let Some(src) = module.declaration_source(db) { |
94 | let frange = original_range(db, src.as_ref().map(|it| it.syntax())); | 94 | let frange = original_range(db, src.as_ref().map(|it| it.syntax())); |
95 | return NavigationTarget::from_syntax( | 95 | let mut res = NavigationTarget::from_syntax( |
96 | frange.file_id, | 96 | frange.file_id, |
97 | name, | 97 | name, |
98 | None, | 98 | None, |
99 | frange.range, | 99 | frange.range, |
100 | src.value.syntax().kind(), | 100 | src.value.syntax().kind(), |
101 | src.value.doc_comment_text(), | ||
102 | src.value.short_label(), | ||
103 | ); | 101 | ); |
102 | res.docs = src.value.doc_comment_text(); | ||
103 | res.description = src.value.short_label(); | ||
104 | return res; | ||
104 | } | 105 | } |
105 | module.to_nav(db) | 106 | module.to_nav(db) |
106 | } | 107 | } |
@@ -130,11 +131,9 @@ impl NavigationTarget { | |||
130 | } | 131 | } |
131 | 132 | ||
132 | /// Allows `NavigationTarget` to be created from a `NameOwner` | 133 | /// Allows `NavigationTarget` to be created from a `NameOwner` |
133 | fn from_named( | 134 | pub(crate) fn from_named( |
134 | db: &RootDatabase, | 135 | db: &RootDatabase, |
135 | node: InFile<&dyn ast::NameOwner>, | 136 | node: InFile<&dyn ast::NameOwner>, |
136 | docs: Option<String>, | ||
137 | description: Option<String>, | ||
138 | ) -> NavigationTarget { | 137 | ) -> NavigationTarget { |
139 | //FIXME: use `_` instead of empty string | 138 | //FIXME: use `_` instead of empty string |
140 | let name = node.value.name().map(|it| it.text().clone()).unwrap_or_default(); | 139 | let name = node.value.name().map(|it| it.text().clone()).unwrap_or_default(); |
@@ -148,8 +147,6 @@ impl NavigationTarget { | |||
148 | focus_range, | 147 | focus_range, |
149 | frange.range, | 148 | frange.range, |
150 | node.value.syntax().kind(), | 149 | node.value.syntax().kind(), |
151 | docs, | ||
152 | description, | ||
153 | ) | 150 | ) |
154 | } | 151 | } |
155 | 152 | ||
@@ -159,8 +156,6 @@ impl NavigationTarget { | |||
159 | focus_range: Option<TextRange>, | 156 | focus_range: Option<TextRange>, |
160 | full_range: TextRange, | 157 | full_range: TextRange, |
161 | kind: SyntaxKind, | 158 | kind: SyntaxKind, |
162 | docs: Option<String>, | ||
163 | description: Option<String>, | ||
164 | ) -> NavigationTarget { | 159 | ) -> NavigationTarget { |
165 | NavigationTarget { | 160 | NavigationTarget { |
166 | file_id, | 161 | file_id, |
@@ -169,8 +164,8 @@ impl NavigationTarget { | |||
169 | full_range, | 164 | full_range, |
170 | focus_range, | 165 | focus_range, |
171 | container_name: None, | 166 | container_name: None, |
172 | description, | 167 | description: None, |
173 | docs, | 168 | docs: None, |
174 | } | 169 | } |
175 | } | 170 | } |
176 | } | 171 | } |
@@ -238,12 +233,11 @@ where | |||
238 | { | 233 | { |
239 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 234 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { |
240 | let src = self.source(db); | 235 | let src = self.source(db); |
241 | NavigationTarget::from_named( | 236 | let mut res = |
242 | db, | 237 | NavigationTarget::from_named(db, src.as_ref().map(|it| it as &dyn ast::NameOwner)); |
243 | src.as_ref().map(|it| it as &dyn ast::NameOwner), | 238 | res.docs = src.value.doc_comment_text(); |
244 | src.value.doc_comment_text(), | 239 | res.description = src.value.short_label(); |
245 | src.value.short_label(), | 240 | res |
246 | ) | ||
247 | } | 241 | } |
248 | } | 242 | } |
249 | 243 | ||
@@ -258,15 +252,7 @@ impl ToNav for hir::Module { | |||
258 | } | 252 | } |
259 | }; | 253 | }; |
260 | let frange = original_range(db, src.with_value(syntax)); | 254 | let frange = original_range(db, src.with_value(syntax)); |
261 | NavigationTarget::from_syntax( | 255 | NavigationTarget::from_syntax(frange.file_id, name, focus, frange.range, syntax.kind()) |
262 | frange.file_id, | ||
263 | name, | ||
264 | focus, | ||
265 | frange.range, | ||
266 | syntax.kind(), | ||
267 | None, | ||
268 | None, | ||
269 | ) | ||
270 | } | 256 | } |
271 | } | 257 | } |
272 | 258 | ||
@@ -285,8 +271,6 @@ impl ToNav for hir::ImplDef { | |||
285 | None, | 271 | None, |
286 | frange.range, | 272 | frange.range, |
287 | src.value.syntax().kind(), | 273 | src.value.syntax().kind(), |
288 | None, | ||
289 | None, | ||
290 | ) | 274 | ) |
291 | } | 275 | } |
292 | } | 276 | } |
@@ -296,12 +280,12 @@ impl ToNav for hir::Field { | |||
296 | let src = self.source(db); | 280 | let src = self.source(db); |
297 | 281 | ||
298 | match &src.value { | 282 | match &src.value { |
299 | FieldSource::Named(it) => NavigationTarget::from_named( | 283 | FieldSource::Named(it) => { |
300 | db, | 284 | let mut res = NavigationTarget::from_named(db, src.with_value(it)); |
301 | src.with_value(it), | 285 | res.docs = it.doc_comment_text(); |
302 | it.doc_comment_text(), | 286 | res.description = it.short_label(); |
303 | it.short_label(), | 287 | res |
304 | ), | 288 | } |
305 | FieldSource::Pos(it) => { | 289 | FieldSource::Pos(it) => { |
306 | let frange = original_range(db, src.with_value(it.syntax())); | 290 | let frange = original_range(db, src.with_value(it.syntax())); |
307 | NavigationTarget::from_syntax( | 291 | NavigationTarget::from_syntax( |
@@ -310,8 +294,6 @@ impl ToNav for hir::Field { | |||
310 | None, | 294 | None, |
311 | frange.range, | 295 | frange.range, |
312 | it.syntax().kind(), | 296 | it.syntax().kind(), |
313 | None, | ||
314 | None, | ||
315 | ) | 297 | ) |
316 | } | 298 | } |
317 | } | 299 | } |
@@ -322,12 +304,10 @@ impl ToNav for hir::MacroDef { | |||
322 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 304 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { |
323 | let src = self.source(db); | 305 | let src = self.source(db); |
324 | log::debug!("nav target {:#?}", src.value.syntax()); | 306 | log::debug!("nav target {:#?}", src.value.syntax()); |
325 | NavigationTarget::from_named( | 307 | let mut res = |
326 | db, | 308 | NavigationTarget::from_named(db, src.as_ref().map(|it| it as &dyn ast::NameOwner)); |
327 | src.as_ref().map(|it| it as &dyn ast::NameOwner), | 309 | res.docs = src.value.doc_comment_text(); |
328 | src.value.doc_comment_text(), | 310 | res |
329 | None, | ||
330 | ) | ||
331 | } | 311 | } |
332 | } | 312 | } |
333 | 313 | ||
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs index 286d45eee..f32ce0d22 100644 --- a/crates/ra_ide/src/runnables.rs +++ b/crates/ra_ide/src/runnables.rs | |||
@@ -1,19 +1,19 @@ | |||
1 | use std::fmt; | ||
2 | |||
1 | use hir::{AsAssocItem, Attrs, HirFileId, InFile, Semantics}; | 3 | use hir::{AsAssocItem, Attrs, HirFileId, InFile, Semantics}; |
2 | use itertools::Itertools; | 4 | use itertools::Itertools; |
5 | use ra_cfg::CfgExpr; | ||
3 | use ra_ide_db::RootDatabase; | 6 | use ra_ide_db::RootDatabase; |
4 | use ra_syntax::{ | 7 | use ra_syntax::{ |
5 | ast::{self, AstNode, AttrsOwner, ModuleItemOwner, NameOwner}, | 8 | ast::{self, AstNode, AttrsOwner, DocCommentsOwner, ModuleItemOwner, NameOwner}, |
6 | match_ast, SyntaxNode, TextRange, | 9 | match_ast, SyntaxNode, |
7 | }; | 10 | }; |
8 | 11 | ||
9 | use crate::FileId; | 12 | use crate::{display::ToNav, FileId, NavigationTarget}; |
10 | use ast::DocCommentsOwner; | ||
11 | use ra_cfg::CfgExpr; | ||
12 | use std::fmt::Display; | ||
13 | 13 | ||
14 | #[derive(Debug)] | 14 | #[derive(Debug)] |
15 | pub struct Runnable { | 15 | pub struct Runnable { |
16 | pub range: TextRange, | 16 | pub nav: NavigationTarget, |
17 | pub kind: RunnableKind, | 17 | pub kind: RunnableKind, |
18 | pub cfg_exprs: Vec<CfgExpr>, | 18 | pub cfg_exprs: Vec<CfgExpr>, |
19 | } | 19 | } |
@@ -24,8 +24,8 @@ pub enum TestId { | |||
24 | Path(String), | 24 | Path(String), |
25 | } | 25 | } |
26 | 26 | ||
27 | impl Display for TestId { | 27 | impl fmt::Display for TestId { |
28 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 28 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
29 | match self { | 29 | match self { |
30 | TestId::Name(name) => write!(f, "{}", name), | 30 | TestId::Name(name) => write!(f, "{}", name), |
31 | TestId::Path(path) => write!(f, "{}", path), | 31 | TestId::Path(path) => write!(f, "{}", path), |
@@ -131,7 +131,8 @@ fn runnable_fn( | |||
131 | let cfg_exprs = | 131 | let cfg_exprs = |
132 | attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect(); | 132 | attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect(); |
133 | 133 | ||
134 | Some(Runnable { range: fn_def.syntax().text_range(), kind, cfg_exprs }) | 134 | let nav = NavigationTarget::from_named(sema.db, InFile::new(file_id.into(), &fn_def)); |
135 | Some(Runnable { nav, kind, cfg_exprs }) | ||
135 | } | 136 | } |
136 | 137 | ||
137 | #[derive(Debug)] | 138 | #[derive(Debug)] |
@@ -183,7 +184,6 @@ fn runnable_mod( | |||
183 | if !has_test_function { | 184 | if !has_test_function { |
184 | return None; | 185 | return None; |
185 | } | 186 | } |
186 | let range = module.syntax().text_range(); | ||
187 | let module_def = sema.to_def(&module)?; | 187 | let module_def = sema.to_def(&module)?; |
188 | 188 | ||
189 | let path = module_def | 189 | let path = module_def |
@@ -197,7 +197,8 @@ fn runnable_mod( | |||
197 | let cfg_exprs = | 197 | let cfg_exprs = |
198 | attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect(); | 198 | attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect(); |
199 | 199 | ||
200 | Some(Runnable { range, kind: RunnableKind::TestMod { path }, cfg_exprs }) | 200 | let nav = module_def.to_nav(sema.db); |
201 | Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg_exprs }) | ||
201 | } | 202 | } |
202 | 203 | ||
203 | #[cfg(test)] | 204 | #[cfg(test)] |
@@ -227,12 +228,38 @@ mod tests { | |||
227 | @r###" | 228 | @r###" |
228 | [ | 229 | [ |
229 | Runnable { | 230 | Runnable { |
230 | range: 1..21, | 231 | nav: NavigationTarget { |
232 | file_id: FileId( | ||
233 | 1, | ||
234 | ), | ||
235 | full_range: 1..21, | ||
236 | name: "main", | ||
237 | kind: FN_DEF, | ||
238 | focus_range: Some( | ||
239 | 12..16, | ||
240 | ), | ||
241 | container_name: None, | ||
242 | description: None, | ||
243 | docs: None, | ||
244 | }, | ||
231 | kind: Bin, | 245 | kind: Bin, |
232 | cfg_exprs: [], | 246 | cfg_exprs: [], |
233 | }, | 247 | }, |
234 | Runnable { | 248 | Runnable { |
235 | range: 22..46, | 249 | nav: NavigationTarget { |
250 | file_id: FileId( | ||
251 | 1, | ||
252 | ), | ||
253 | full_range: 22..46, | ||
254 | name: "test_foo", | ||
255 | kind: FN_DEF, | ||
256 | focus_range: Some( | ||
257 | 33..41, | ||
258 | ), | ||
259 | container_name: None, | ||
260 | description: None, | ||
261 | docs: None, | ||
262 | }, | ||
236 | kind: Test { | 263 | kind: Test { |
237 | test_id: Path( | 264 | test_id: Path( |
238 | "test_foo", | 265 | "test_foo", |
@@ -244,7 +271,20 @@ mod tests { | |||
244 | cfg_exprs: [], | 271 | cfg_exprs: [], |
245 | }, | 272 | }, |
246 | Runnable { | 273 | Runnable { |
247 | range: 47..81, | 274 | nav: NavigationTarget { |
275 | file_id: FileId( | ||
276 | 1, | ||
277 | ), | ||
278 | full_range: 47..81, | ||
279 | name: "test_foo", | ||
280 | kind: FN_DEF, | ||
281 | focus_range: Some( | ||
282 | 68..76, | ||
283 | ), | ||
284 | container_name: None, | ||
285 | description: None, | ||
286 | docs: None, | ||
287 | }, | ||
248 | kind: Test { | 288 | kind: Test { |
249 | test_id: Path( | 289 | test_id: Path( |
250 | "test_foo", | 290 | "test_foo", |
@@ -279,12 +319,38 @@ mod tests { | |||
279 | @r###" | 319 | @r###" |
280 | [ | 320 | [ |
281 | Runnable { | 321 | Runnable { |
282 | range: 1..21, | 322 | nav: NavigationTarget { |
323 | file_id: FileId( | ||
324 | 1, | ||
325 | ), | ||
326 | full_range: 1..21, | ||
327 | name: "main", | ||
328 | kind: FN_DEF, | ||
329 | focus_range: Some( | ||
330 | 12..16, | ||
331 | ), | ||
332 | container_name: None, | ||
333 | description: None, | ||
334 | docs: None, | ||
335 | }, | ||
283 | kind: Bin, | 336 | kind: Bin, |
284 | cfg_exprs: [], | 337 | cfg_exprs: [], |
285 | }, | 338 | }, |
286 | Runnable { | 339 | Runnable { |
287 | range: 22..64, | 340 | nav: NavigationTarget { |
341 | file_id: FileId( | ||
342 | 1, | ||
343 | ), | ||
344 | full_range: 22..64, | ||
345 | name: "foo", | ||
346 | kind: FN_DEF, | ||
347 | focus_range: Some( | ||
348 | 56..59, | ||
349 | ), | ||
350 | container_name: None, | ||
351 | description: None, | ||
352 | docs: None, | ||
353 | }, | ||
288 | kind: DocTest { | 354 | kind: DocTest { |
289 | test_id: Path( | 355 | test_id: Path( |
290 | "foo", | 356 | "foo", |
@@ -319,12 +385,38 @@ mod tests { | |||
319 | @r###" | 385 | @r###" |
320 | [ | 386 | [ |
321 | Runnable { | 387 | Runnable { |
322 | range: 1..21, | 388 | nav: NavigationTarget { |
389 | file_id: FileId( | ||
390 | 1, | ||
391 | ), | ||
392 | full_range: 1..21, | ||
393 | name: "main", | ||
394 | kind: FN_DEF, | ||
395 | focus_range: Some( | ||
396 | 12..16, | ||
397 | ), | ||
398 | container_name: None, | ||
399 | description: None, | ||
400 | docs: None, | ||
401 | }, | ||
323 | kind: Bin, | 402 | kind: Bin, |
324 | cfg_exprs: [], | 403 | cfg_exprs: [], |
325 | }, | 404 | }, |
326 | Runnable { | 405 | Runnable { |
327 | range: 51..105, | 406 | nav: NavigationTarget { |
407 | file_id: FileId( | ||
408 | 1, | ||
409 | ), | ||
410 | full_range: 51..105, | ||
411 | name: "foo", | ||
412 | kind: FN_DEF, | ||
413 | focus_range: Some( | ||
414 | 97..100, | ||
415 | ), | ||
416 | container_name: None, | ||
417 | description: None, | ||
418 | docs: None, | ||
419 | }, | ||
328 | kind: DocTest { | 420 | kind: DocTest { |
329 | test_id: Path( | 421 | test_id: Path( |
330 | "Data::foo", | 422 | "Data::foo", |
@@ -354,14 +446,40 @@ mod tests { | |||
354 | @r###" | 446 | @r###" |
355 | [ | 447 | [ |
356 | Runnable { | 448 | Runnable { |
357 | range: 1..59, | 449 | nav: NavigationTarget { |
450 | file_id: FileId( | ||
451 | 1, | ||
452 | ), | ||
453 | full_range: 1..59, | ||
454 | name: "test_mod", | ||
455 | kind: MODULE, | ||
456 | focus_range: Some( | ||
457 | 13..21, | ||
458 | ), | ||
459 | container_name: None, | ||
460 | description: None, | ||
461 | docs: None, | ||
462 | }, | ||
358 | kind: TestMod { | 463 | kind: TestMod { |
359 | path: "test_mod", | 464 | path: "test_mod", |
360 | }, | 465 | }, |
361 | cfg_exprs: [], | 466 | cfg_exprs: [], |
362 | }, | 467 | }, |
363 | Runnable { | 468 | Runnable { |
364 | range: 28..57, | 469 | nav: NavigationTarget { |
470 | file_id: FileId( | ||
471 | 1, | ||
472 | ), | ||
473 | full_range: 28..57, | ||
474 | name: "test_foo1", | ||
475 | kind: FN_DEF, | ||
476 | focus_range: Some( | ||
477 | 43..52, | ||
478 | ), | ||
479 | container_name: None, | ||
480 | description: None, | ||
481 | docs: None, | ||
482 | }, | ||
365 | kind: Test { | 483 | kind: Test { |
366 | test_id: Path( | 484 | test_id: Path( |
367 | "test_mod::test_foo1", | 485 | "test_mod::test_foo1", |
@@ -396,14 +514,40 @@ mod tests { | |||
396 | @r###" | 514 | @r###" |
397 | [ | 515 | [ |
398 | Runnable { | 516 | Runnable { |
399 | range: 23..85, | 517 | nav: NavigationTarget { |
518 | file_id: FileId( | ||
519 | 1, | ||
520 | ), | ||
521 | full_range: 23..85, | ||
522 | name: "test_mod", | ||
523 | kind: MODULE, | ||
524 | focus_range: Some( | ||
525 | 27..35, | ||
526 | ), | ||
527 | container_name: None, | ||
528 | description: None, | ||
529 | docs: None, | ||
530 | }, | ||
400 | kind: TestMod { | 531 | kind: TestMod { |
401 | path: "foo::test_mod", | 532 | path: "foo::test_mod", |
402 | }, | 533 | }, |
403 | cfg_exprs: [], | 534 | cfg_exprs: [], |
404 | }, | 535 | }, |
405 | Runnable { | 536 | Runnable { |
406 | range: 46..79, | 537 | nav: NavigationTarget { |
538 | file_id: FileId( | ||
539 | 1, | ||
540 | ), | ||
541 | full_range: 46..79, | ||
542 | name: "test_foo1", | ||
543 | kind: FN_DEF, | ||
544 | focus_range: Some( | ||
545 | 65..74, | ||
546 | ), | ||
547 | container_name: None, | ||
548 | description: None, | ||
549 | docs: None, | ||
550 | }, | ||
407 | kind: Test { | 551 | kind: Test { |
408 | test_id: Path( | 552 | test_id: Path( |
409 | "foo::test_mod::test_foo1", | 553 | "foo::test_mod::test_foo1", |
@@ -440,14 +584,40 @@ mod tests { | |||
440 | @r###" | 584 | @r###" |
441 | [ | 585 | [ |
442 | Runnable { | 586 | Runnable { |
443 | range: 41..115, | 587 | nav: NavigationTarget { |
588 | file_id: FileId( | ||
589 | 1, | ||
590 | ), | ||
591 | full_range: 41..115, | ||
592 | name: "test_mod", | ||
593 | kind: MODULE, | ||
594 | focus_range: Some( | ||
595 | 45..53, | ||
596 | ), | ||
597 | container_name: None, | ||
598 | description: None, | ||
599 | docs: None, | ||
600 | }, | ||
444 | kind: TestMod { | 601 | kind: TestMod { |
445 | path: "foo::bar::test_mod", | 602 | path: "foo::bar::test_mod", |
446 | }, | 603 | }, |
447 | cfg_exprs: [], | 604 | cfg_exprs: [], |
448 | }, | 605 | }, |
449 | Runnable { | 606 | Runnable { |
450 | range: 68..105, | 607 | nav: NavigationTarget { |
608 | file_id: FileId( | ||
609 | 1, | ||
610 | ), | ||
611 | full_range: 68..105, | ||
612 | name: "test_foo1", | ||
613 | kind: FN_DEF, | ||
614 | focus_range: Some( | ||
615 | 91..100, | ||
616 | ), | ||
617 | container_name: None, | ||
618 | description: None, | ||
619 | docs: None, | ||
620 | }, | ||
451 | kind: Test { | 621 | kind: Test { |
452 | test_id: Path( | 622 | test_id: Path( |
453 | "foo::bar::test_mod::test_foo1", | 623 | "foo::bar::test_mod::test_foo1", |
@@ -479,7 +649,20 @@ mod tests { | |||
479 | @r###" | 649 | @r###" |
480 | [ | 650 | [ |
481 | Runnable { | 651 | Runnable { |
482 | range: 1..58, | 652 | nav: NavigationTarget { |
653 | file_id: FileId( | ||
654 | 1, | ||
655 | ), | ||
656 | full_range: 1..58, | ||
657 | name: "test_foo1", | ||
658 | kind: FN_DEF, | ||
659 | focus_range: Some( | ||
660 | 44..53, | ||
661 | ), | ||
662 | container_name: None, | ||
663 | description: None, | ||
664 | docs: None, | ||
665 | }, | ||
483 | kind: Test { | 666 | kind: Test { |
484 | test_id: Path( | 667 | test_id: Path( |
485 | "test_foo1", | 668 | "test_foo1", |
@@ -516,7 +699,20 @@ mod tests { | |||
516 | @r###" | 699 | @r###" |
517 | [ | 700 | [ |
518 | Runnable { | 701 | Runnable { |
519 | range: 1..80, | 702 | nav: NavigationTarget { |
703 | file_id: FileId( | ||
704 | 1, | ||
705 | ), | ||
706 | full_range: 1..80, | ||
707 | name: "test_foo1", | ||
708 | kind: FN_DEF, | ||
709 | focus_range: Some( | ||
710 | 66..75, | ||
711 | ), | ||
712 | container_name: None, | ||
713 | description: None, | ||
714 | docs: None, | ||
715 | }, | ||
520 | kind: Test { | 716 | kind: Test { |
521 | test_id: Path( | 717 | test_id: Path( |
522 | "test_foo1", | 718 | "test_foo1", |
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index a306ce95f..4b7444039 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs | |||
@@ -64,7 +64,7 @@ impl Default for CargoConfig { | |||
64 | fn default() -> Self { | 64 | fn default() -> Self { |
65 | CargoConfig { | 65 | CargoConfig { |
66 | no_default_features: false, | 66 | no_default_features: false, |
67 | all_features: true, | 67 | all_features: false, |
68 | features: Vec::new(), | 68 | features: Vec::new(), |
69 | load_out_dirs_from_check: false, | 69 | load_out_dirs_from_check: false, |
70 | target: None, | 70 | target: None, |
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs index 345693524..673795e78 100644 --- a/crates/rust-analyzer/src/caps.rs +++ b/crates/rust-analyzer/src/caps.rs | |||
@@ -87,6 +87,9 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti | |||
87 | "ssr": true, | 87 | "ssr": true, |
88 | "onEnter": true, | 88 | "onEnter": true, |
89 | "parentModule": true, | 89 | "parentModule": true, |
90 | "runnables": { | ||
91 | "kinds": [ "cargo" ], | ||
92 | }, | ||
90 | })), | 93 | })), |
91 | } | 94 | } |
92 | } | 95 | } |
diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs index 441fb61df..008518a08 100644 --- a/crates/rust-analyzer/src/cargo_target_spec.rs +++ b/crates/rust-analyzer/src/cargo_target_spec.rs | |||
@@ -1,10 +1,10 @@ | |||
1 | //! See `CargoTargetSpec` | 1 | //! See `CargoTargetSpec` |
2 | 2 | ||
3 | use ra_cfg::CfgExpr; | ||
3 | use ra_ide::{FileId, RunnableKind, TestId}; | 4 | use ra_ide::{FileId, RunnableKind, TestId}; |
4 | use ra_project_model::{self, ProjectWorkspace, TargetKind}; | 5 | use ra_project_model::{self, ProjectWorkspace, TargetKind}; |
5 | 6 | ||
6 | use crate::{world::WorldSnapshot, Result}; | 7 | use crate::{world::WorldSnapshot, Result}; |
7 | use ra_syntax::SmolStr; | ||
8 | 8 | ||
9 | /// Abstract representation of Cargo target. | 9 | /// Abstract representation of Cargo target. |
10 | /// | 10 | /// |
@@ -21,7 +21,7 @@ impl CargoTargetSpec { | |||
21 | pub(crate) fn runnable_args( | 21 | pub(crate) fn runnable_args( |
22 | spec: Option<CargoTargetSpec>, | 22 | spec: Option<CargoTargetSpec>, |
23 | kind: &RunnableKind, | 23 | kind: &RunnableKind, |
24 | features_needed: &Vec<SmolStr>, | 24 | cfgs: &[CfgExpr], |
25 | ) -> Result<(Vec<String>, Vec<String>)> { | 25 | ) -> Result<(Vec<String>, Vec<String>)> { |
26 | let mut args = Vec::new(); | 26 | let mut args = Vec::new(); |
27 | let mut extra_args = Vec::new(); | 27 | let mut extra_args = Vec::new(); |
@@ -76,10 +76,14 @@ impl CargoTargetSpec { | |||
76 | } | 76 | } |
77 | } | 77 | } |
78 | 78 | ||
79 | features_needed.iter().for_each(|feature| { | 79 | let mut features = Vec::new(); |
80 | for cfg in cfgs { | ||
81 | required_features(cfg, &mut features); | ||
82 | } | ||
83 | for feature in features { | ||
80 | args.push("--features".to_string()); | 84 | args.push("--features".to_string()); |
81 | args.push(feature.to_string()); | 85 | args.push(feature); |
82 | }); | 86 | } |
83 | 87 | ||
84 | Ok((args, extra_args)) | 88 | Ok((args, extra_args)) |
85 | } | 89 | } |
@@ -140,3 +144,74 @@ impl CargoTargetSpec { | |||
140 | } | 144 | } |
141 | } | 145 | } |
142 | } | 146 | } |
147 | |||
148 | /// Fill minimal features needed | ||
149 | fn required_features(cfg_expr: &CfgExpr, features: &mut Vec<String>) { | ||
150 | match cfg_expr { | ||
151 | CfgExpr::KeyValue { key, value } if key == "feature" => features.push(value.to_string()), | ||
152 | CfgExpr::All(preds) => { | ||
153 | preds.iter().for_each(|cfg| required_features(cfg, features)); | ||
154 | } | ||
155 | CfgExpr::Any(preds) => { | ||
156 | for cfg in preds { | ||
157 | let len_features = features.len(); | ||
158 | required_features(cfg, features); | ||
159 | if len_features != features.len() { | ||
160 | break; | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | _ => {} | ||
165 | } | ||
166 | } | ||
167 | |||
168 | #[cfg(test)] | ||
169 | mod tests { | ||
170 | use super::*; | ||
171 | |||
172 | use mbe::{ast_to_token_tree, TokenMap}; | ||
173 | use ra_cfg::parse_cfg; | ||
174 | use ra_syntax::{ | ||
175 | ast::{self, AstNode}, | ||
176 | SmolStr, | ||
177 | }; | ||
178 | |||
179 | fn get_token_tree_generated(input: &str) -> (tt::Subtree, TokenMap) { | ||
180 | let source_file = ast::SourceFile::parse(input).ok().unwrap(); | ||
181 | let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); | ||
182 | ast_to_token_tree(&tt).unwrap() | ||
183 | } | ||
184 | |||
185 | #[test] | ||
186 | fn test_cfg_expr_minimal_features_needed() { | ||
187 | let (subtree, _) = get_token_tree_generated(r#"#![cfg(feature = "baz")]"#); | ||
188 | let cfg_expr = parse_cfg(&subtree); | ||
189 | let mut min_features = vec![]; | ||
190 | required_features(&cfg_expr, &mut min_features); | ||
191 | |||
192 | assert_eq!(min_features, vec![SmolStr::new("baz")]); | ||
193 | |||
194 | let (subtree, _) = | ||
195 | get_token_tree_generated(r#"#![cfg(all(feature = "baz", feature = "foo"))]"#); | ||
196 | let cfg_expr = parse_cfg(&subtree); | ||
197 | |||
198 | let mut min_features = vec![]; | ||
199 | required_features(&cfg_expr, &mut min_features); | ||
200 | assert_eq!(min_features, vec![SmolStr::new("baz"), SmolStr::new("foo")]); | ||
201 | |||
202 | let (subtree, _) = | ||
203 | get_token_tree_generated(r#"#![cfg(any(feature = "baz", feature = "foo", unix))]"#); | ||
204 | let cfg_expr = parse_cfg(&subtree); | ||
205 | |||
206 | let mut min_features = vec![]; | ||
207 | required_features(&cfg_expr, &mut min_features); | ||
208 | assert_eq!(min_features, vec![SmolStr::new("baz")]); | ||
209 | |||
210 | let (subtree, _) = get_token_tree_generated(r#"#![cfg(foo)]"#); | ||
211 | let cfg_expr = parse_cfg(&subtree); | ||
212 | |||
213 | let mut min_features = vec![]; | ||
214 | required_features(&cfg_expr, &mut min_features); | ||
215 | assert!(min_features.is_empty()); | ||
216 | } | ||
217 | } | ||
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 9e8e7ab82..3337078ac 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -123,7 +123,7 @@ impl Default for Config { | |||
123 | check: Some(FlycheckConfig::CargoCommand { | 123 | check: Some(FlycheckConfig::CargoCommand { |
124 | command: "check".to_string(), | 124 | command: "check".to_string(), |
125 | all_targets: true, | 125 | all_targets: true, |
126 | all_features: true, | 126 | all_features: false, |
127 | extra_args: Vec::new(), | 127 | extra_args: Vec::new(), |
128 | }), | 128 | }), |
129 | 129 | ||
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 05b76e7c8..4b436c301 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs | |||
@@ -4,7 +4,6 @@ use std::{collections::HashMap, path::PathBuf}; | |||
4 | 4 | ||
5 | use lsp_types::request::Request; | 5 | use lsp_types::request::Request; |
6 | use lsp_types::{Position, Range, TextDocumentIdentifier}; | 6 | use lsp_types::{Position, Range, TextDocumentIdentifier}; |
7 | use rustc_hash::FxHashMap; | ||
8 | use serde::{Deserialize, Serialize}; | 7 | use serde::{Deserialize, Serialize}; |
9 | 8 | ||
10 | pub enum AnalyzerStatus {} | 9 | pub enum AnalyzerStatus {} |
@@ -128,7 +127,7 @@ pub enum Runnables {} | |||
128 | impl Request for Runnables { | 127 | impl Request for Runnables { |
129 | type Params = RunnablesParams; | 128 | type Params = RunnablesParams; |
130 | type Result = Vec<Runnable>; | 129 | type Result = Vec<Runnable>; |
131 | const METHOD: &'static str = "rust-analyzer/runnables"; | 130 | const METHOD: &'static str = "experimental/runnables"; |
132 | } | 131 | } |
133 | 132 | ||
134 | #[derive(Serialize, Deserialize, Debug)] | 133 | #[derive(Serialize, Deserialize, Debug)] |
@@ -138,25 +137,31 @@ pub struct RunnablesParams { | |||
138 | pub position: Option<Position>, | 137 | pub position: Option<Position>, |
139 | } | 138 | } |
140 | 139 | ||
141 | // Must strictly correspond to the executable name | 140 | #[derive(Deserialize, Serialize, Debug)] |
141 | #[serde(rename_all = "camelCase")] | ||
142 | pub struct Runnable { | ||
143 | pub label: String, | ||
144 | #[serde(skip_serializing_if = "Option::is_none")] | ||
145 | pub location: Option<lsp_types::LocationLink>, | ||
146 | pub kind: RunnableKind, | ||
147 | pub args: CargoRunnable, | ||
148 | } | ||
149 | |||
142 | #[derive(Serialize, Deserialize, Debug)] | 150 | #[derive(Serialize, Deserialize, Debug)] |
143 | #[serde(rename_all = "lowercase")] | 151 | #[serde(rename_all = "lowercase")] |
144 | pub enum RunnableKind { | 152 | pub enum RunnableKind { |
145 | Cargo, | 153 | Cargo, |
146 | Rustc, | ||
147 | Rustup, | ||
148 | } | 154 | } |
149 | 155 | ||
150 | #[derive(Deserialize, Serialize, Debug)] | 156 | #[derive(Deserialize, Serialize, Debug)] |
151 | #[serde(rename_all = "camelCase")] | 157 | #[serde(rename_all = "camelCase")] |
152 | pub struct Runnable { | 158 | pub struct CargoRunnable { |
153 | pub range: Range, | 159 | #[serde(skip_serializing_if = "Option::is_none")] |
154 | pub label: String, | 160 | pub workspace_root: Option<PathBuf>, |
155 | pub kind: RunnableKind, | 161 | // command, --package and --lib stuff |
156 | pub args: Vec<String>, | 162 | pub cargo_args: Vec<String>, |
157 | pub extra_args: Vec<String>, | 163 | // stuff after -- |
158 | pub env: FxHashMap<String, String>, | 164 | pub executable_args: Vec<String>, |
159 | pub cwd: Option<PathBuf>, | ||
160 | } | 165 | } |
161 | 166 | ||
162 | pub enum InlayHints {} | 167 | pub enum InlayHints {} |
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index b342f4bb7..3c4064441 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs | |||
@@ -17,15 +17,12 @@ use lsp_types::{ | |||
17 | SemanticTokensParams, SemanticTokensRangeParams, SemanticTokensRangeResult, | 17 | SemanticTokensParams, SemanticTokensRangeParams, SemanticTokensRangeResult, |
18 | SemanticTokensResult, SymbolInformation, TextDocumentIdentifier, Url, WorkspaceEdit, | 18 | SemanticTokensResult, SymbolInformation, TextDocumentIdentifier, Url, WorkspaceEdit, |
19 | }; | 19 | }; |
20 | use ra_cfg::CfgExpr; | ||
21 | use ra_ide::{ | 20 | use ra_ide::{ |
22 | FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, SearchScope, | 21 | FileId, FilePosition, FileRange, Query, RangeInfo, RunnableKind, SearchScope, TextEdit, |
23 | TextEdit, | ||
24 | }; | 22 | }; |
25 | use ra_prof::profile; | 23 | use ra_prof::profile; |
26 | use ra_project_model::TargetKind; | 24 | use ra_project_model::TargetKind; |
27 | use ra_syntax::{AstNode, SmolStr, SyntaxKind, TextRange, TextSize}; | 25 | use ra_syntax::{AstNode, SyntaxKind, TextRange, TextSize}; |
28 | use rustc_hash::FxHashMap; | ||
29 | use serde::{Deserialize, Serialize}; | 26 | use serde::{Deserialize, Serialize}; |
30 | use serde_json::to_value; | 27 | use serde_json::to_value; |
31 | use stdx::format_to; | 28 | use stdx::format_to; |
@@ -403,7 +400,7 @@ pub fn handle_runnables( | |||
403 | let cargo_spec = CargoTargetSpec::for_file(&world, file_id)?; | 400 | let cargo_spec = CargoTargetSpec::for_file(&world, file_id)?; |
404 | for runnable in world.analysis().runnables(file_id)? { | 401 | for runnable in world.analysis().runnables(file_id)? { |
405 | if let Some(offset) = offset { | 402 | if let Some(offset) = offset { |
406 | if !runnable.range.contains_inclusive(offset) { | 403 | if !runnable.nav.full_range().contains_inclusive(offset) { |
407 | continue; | 404 | continue; |
408 | } | 405 | } |
409 | } | 406 | } |
@@ -416,7 +413,7 @@ pub fn handle_runnables( | |||
416 | } | 413 | } |
417 | } | 414 | } |
418 | } | 415 | } |
419 | res.push(to_lsp_runnable(&world, file_id, runnable)?); | 416 | res.push(to_proto::runnable(&world, file_id, runnable)?); |
420 | } | 417 | } |
421 | 418 | ||
422 | // Add `cargo check` and `cargo test` for the whole package | 419 | // Add `cargo check` and `cargo test` for the whole package |
@@ -424,25 +421,31 @@ pub fn handle_runnables( | |||
424 | Some(spec) => { | 421 | Some(spec) => { |
425 | for &cmd in ["check", "test"].iter() { | 422 | for &cmd in ["check", "test"].iter() { |
426 | res.push(lsp_ext::Runnable { | 423 | res.push(lsp_ext::Runnable { |
427 | range: Default::default(), | ||
428 | label: format!("cargo {} -p {}", cmd, spec.package), | 424 | label: format!("cargo {} -p {}", cmd, spec.package), |
425 | location: None, | ||
429 | kind: lsp_ext::RunnableKind::Cargo, | 426 | kind: lsp_ext::RunnableKind::Cargo, |
430 | args: vec![cmd.to_string(), "--package".to_string(), spec.package.clone()], | 427 | args: lsp_ext::CargoRunnable { |
431 | extra_args: Vec::new(), | 428 | workspace_root: workspace_root.map(|root| root.to_owned()), |
432 | env: FxHashMap::default(), | 429 | cargo_args: vec![ |
433 | cwd: workspace_root.map(|root| root.to_owned()), | 430 | cmd.to_string(), |
431 | "--package".to_string(), | ||
432 | spec.package.clone(), | ||
433 | ], | ||
434 | executable_args: Vec::new(), | ||
435 | }, | ||
434 | }) | 436 | }) |
435 | } | 437 | } |
436 | } | 438 | } |
437 | None => { | 439 | None => { |
438 | res.push(lsp_ext::Runnable { | 440 | res.push(lsp_ext::Runnable { |
439 | range: Default::default(), | ||
440 | label: "cargo check --workspace".to_string(), | 441 | label: "cargo check --workspace".to_string(), |
442 | location: None, | ||
441 | kind: lsp_ext::RunnableKind::Cargo, | 443 | kind: lsp_ext::RunnableKind::Cargo, |
442 | args: vec!["check".to_string(), "--workspace".to_string()], | 444 | args: lsp_ext::CargoRunnable { |
443 | extra_args: Vec::new(), | 445 | workspace_root: workspace_root.map(|root| root.to_owned()), |
444 | env: FxHashMap::default(), | 446 | cargo_args: vec!["check".to_string(), "--workspace".to_string()], |
445 | cwd: workspace_root.map(|root| root.to_owned()), | 447 | executable_args: Vec::new(), |
448 | }, | ||
446 | }); | 449 | }); |
447 | } | 450 | } |
448 | } | 451 | } |
@@ -755,11 +758,11 @@ pub fn handle_code_action( | |||
755 | if world.config.client_caps.resolve_code_action { | 758 | if world.config.client_caps.resolve_code_action { |
756 | for assist in world.analysis().unresolved_assists(&world.config.assist, frange)?.into_iter() | 759 | for assist in world.analysis().unresolved_assists(&world.config.assist, frange)?.into_iter() |
757 | { | 760 | { |
758 | res.push(to_proto::unresolved_code_action(&world, assist)?.into()); | 761 | res.push(to_proto::unresolved_code_action(&world, assist)?); |
759 | } | 762 | } |
760 | } else { | 763 | } else { |
761 | for assist in world.analysis().resolved_assists(&world.config.assist, frange)?.into_iter() { | 764 | for assist in world.analysis().resolved_assists(&world.config.assist, frange)?.into_iter() { |
762 | res.push(to_proto::resolved_code_action(&world, assist)?.into()); | 765 | res.push(to_proto::resolved_code_action(&world, assist)?); |
763 | } | 766 | } |
764 | } | 767 | } |
765 | 768 | ||
@@ -782,7 +785,7 @@ pub fn handle_resolve_code_action( | |||
782 | let mut res: Vec<lsp_ext::CodeAction> = Vec::new(); | 785 | let mut res: Vec<lsp_ext::CodeAction> = Vec::new(); |
783 | 786 | ||
784 | for assist in world.analysis().resolved_assists(&world.config.assist, frange)?.into_iter() { | 787 | for assist in world.analysis().resolved_assists(&world.config.assist, frange)?.into_iter() { |
785 | res.push(to_proto::resolved_code_action(&world, assist)?.into()); | 788 | res.push(to_proto::resolved_code_action(&world, assist)?); |
786 | } | 789 | } |
787 | Ok(res | 790 | Ok(res |
788 | .into_iter() | 791 | .into_iter() |
@@ -833,10 +836,11 @@ pub fn handle_code_lens( | |||
833 | } | 836 | } |
834 | }; | 837 | }; |
835 | 838 | ||
836 | let mut r = to_lsp_runnable(&world, file_id, runnable)?; | 839 | let range = to_proto::range(&line_index, runnable.nav.range()); |
840 | let r = to_proto::runnable(&world, file_id, runnable)?; | ||
837 | if world.config.lens.run { | 841 | if world.config.lens.run { |
838 | let lens = CodeLens { | 842 | let lens = CodeLens { |
839 | range: r.range, | 843 | range, |
840 | command: Some(Command { | 844 | command: Some(Command { |
841 | title: run_title.to_string(), | 845 | title: run_title.to_string(), |
842 | command: "rust-analyzer.runSingle".into(), | 846 | command: "rust-analyzer.runSingle".into(), |
@@ -848,13 +852,8 @@ pub fn handle_code_lens( | |||
848 | } | 852 | } |
849 | 853 | ||
850 | if debugee && world.config.lens.debug { | 854 | if debugee && world.config.lens.debug { |
851 | if r.args[0] == "run" { | ||
852 | r.args[0] = "build".into(); | ||
853 | } else { | ||
854 | r.args.push("--no-run".into()); | ||
855 | } | ||
856 | let debug_lens = CodeLens { | 855 | let debug_lens = CodeLens { |
857 | range: r.range, | 856 | range, |
858 | command: Some(Command { | 857 | command: Some(Command { |
859 | title: "Debug".into(), | 858 | title: "Debug".into(), |
860 | command: "rust-analyzer.debugSingle".into(), | 859 | command: "rust-analyzer.debugSingle".into(), |
@@ -1008,65 +1007,6 @@ pub fn publish_diagnostics(world: &WorldSnapshot, file_id: FileId) -> Result<Dia | |||
1008 | Ok(DiagnosticTask::SetNative(file_id, diagnostics)) | 1007 | Ok(DiagnosticTask::SetNative(file_id, diagnostics)) |
1009 | } | 1008 | } |
1010 | 1009 | ||
1011 | fn to_lsp_runnable( | ||
1012 | world: &WorldSnapshot, | ||
1013 | file_id: FileId, | ||
1014 | runnable: Runnable, | ||
1015 | ) -> Result<lsp_ext::Runnable> { | ||
1016 | let spec = CargoTargetSpec::for_file(world, file_id)?; | ||
1017 | let target = spec.as_ref().map(|s| s.target.clone()); | ||
1018 | let mut features_needed = vec![]; | ||
1019 | for cfg_expr in &runnable.cfg_exprs { | ||
1020 | collect_minimal_features_needed(cfg_expr, &mut features_needed); | ||
1021 | } | ||
1022 | let (args, extra_args) = | ||
1023 | CargoTargetSpec::runnable_args(spec, &runnable.kind, &features_needed)?; | ||
1024 | let line_index = world.analysis().file_line_index(file_id)?; | ||
1025 | let label = match &runnable.kind { | ||
1026 | RunnableKind::Test { test_id, .. } => format!("test {}", test_id), | ||
1027 | RunnableKind::TestMod { path } => format!("test-mod {}", path), | ||
1028 | RunnableKind::Bench { test_id } => format!("bench {}", test_id), | ||
1029 | RunnableKind::DocTest { test_id, .. } => format!("doctest {}", test_id), | ||
1030 | RunnableKind::Bin => { | ||
1031 | target.map_or_else(|| "run binary".to_string(), |t| format!("run {}", t)) | ||
1032 | } | ||
1033 | }; | ||
1034 | |||
1035 | Ok(lsp_ext::Runnable { | ||
1036 | range: to_proto::range(&line_index, runnable.range), | ||
1037 | label, | ||
1038 | kind: lsp_ext::RunnableKind::Cargo, | ||
1039 | args, | ||
1040 | extra_args, | ||
1041 | env: { | ||
1042 | let mut m = FxHashMap::default(); | ||
1043 | m.insert("RUST_BACKTRACE".to_string(), "short".to_string()); | ||
1044 | m | ||
1045 | }, | ||
1046 | cwd: world.workspace_root_for(file_id).map(|root| root.to_owned()), | ||
1047 | }) | ||
1048 | } | ||
1049 | |||
1050 | /// Fill minimal features needed | ||
1051 | fn collect_minimal_features_needed(cfg_expr: &CfgExpr, features: &mut Vec<SmolStr>) { | ||
1052 | match cfg_expr { | ||
1053 | CfgExpr::KeyValue { key, value } if key == "feature" => features.push(value.clone()), | ||
1054 | CfgExpr::All(preds) => { | ||
1055 | preds.iter().for_each(|cfg| collect_minimal_features_needed(cfg, features)); | ||
1056 | } | ||
1057 | CfgExpr::Any(preds) => { | ||
1058 | for cfg in preds { | ||
1059 | let len_features = features.len(); | ||
1060 | collect_minimal_features_needed(cfg, features); | ||
1061 | if len_features != features.len() { | ||
1062 | break; | ||
1063 | } | ||
1064 | } | ||
1065 | } | ||
1066 | _ => {} | ||
1067 | } | ||
1068 | } | ||
1069 | |||
1070 | pub fn handle_inlay_hints( | 1010 | pub fn handle_inlay_hints( |
1071 | world: WorldSnapshot, | 1011 | world: WorldSnapshot, |
1072 | params: InlayHintsParams, | 1012 | params: InlayHintsParams, |
@@ -1203,54 +1143,3 @@ pub fn handle_semantic_tokens_range( | |||
1203 | let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); | 1143 | let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); |
1204 | Ok(Some(semantic_tokens.into())) | 1144 | Ok(Some(semantic_tokens.into())) |
1205 | } | 1145 | } |
1206 | |||
1207 | #[cfg(test)] | ||
1208 | mod tests { | ||
1209 | use super::*; | ||
1210 | |||
1211 | use mbe::{ast_to_token_tree, TokenMap}; | ||
1212 | use ra_cfg::parse_cfg; | ||
1213 | use ra_syntax::{ | ||
1214 | ast::{self, AstNode}, | ||
1215 | SmolStr, | ||
1216 | }; | ||
1217 | |||
1218 | fn get_token_tree_generated(input: &str) -> (tt::Subtree, TokenMap) { | ||
1219 | let source_file = ast::SourceFile::parse(input).ok().unwrap(); | ||
1220 | let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); | ||
1221 | ast_to_token_tree(&tt).unwrap() | ||
1222 | } | ||
1223 | |||
1224 | #[test] | ||
1225 | fn test_cfg_expr_minimal_features_needed() { | ||
1226 | let (subtree, _) = get_token_tree_generated(r#"#![cfg(feature = "baz")]"#); | ||
1227 | let cfg_expr = parse_cfg(&subtree); | ||
1228 | let mut min_features = vec![]; | ||
1229 | collect_minimal_features_needed(&cfg_expr, &mut min_features); | ||
1230 | |||
1231 | assert_eq!(min_features, vec![SmolStr::new("baz")]); | ||
1232 | |||
1233 | let (subtree, _) = | ||
1234 | get_token_tree_generated(r#"#![cfg(all(feature = "baz", feature = "foo"))]"#); | ||
1235 | let cfg_expr = parse_cfg(&subtree); | ||
1236 | |||
1237 | let mut min_features = vec![]; | ||
1238 | collect_minimal_features_needed(&cfg_expr, &mut min_features); | ||
1239 | assert_eq!(min_features, vec![SmolStr::new("baz"), SmolStr::new("foo")]); | ||
1240 | |||
1241 | let (subtree, _) = | ||
1242 | get_token_tree_generated(r#"#![cfg(any(feature = "baz", feature = "foo", unix))]"#); | ||
1243 | let cfg_expr = parse_cfg(&subtree); | ||
1244 | |||
1245 | let mut min_features = vec![]; | ||
1246 | collect_minimal_features_needed(&cfg_expr, &mut min_features); | ||
1247 | assert_eq!(min_features, vec![SmolStr::new("baz")]); | ||
1248 | |||
1249 | let (subtree, _) = get_token_tree_generated(r#"#![cfg(foo)]"#); | ||
1250 | let cfg_expr = parse_cfg(&subtree); | ||
1251 | |||
1252 | let mut min_features = vec![]; | ||
1253 | collect_minimal_features_needed(&cfg_expr, &mut min_features); | ||
1254 | assert!(min_features.is_empty()); | ||
1255 | } | ||
1256 | } | ||
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index db78c4b5c..3672b1a26 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -4,12 +4,14 @@ use ra_ide::{ | |||
4 | Assist, CompletionItem, CompletionItemKind, Documentation, FileSystemEdit, Fold, FoldKind, | 4 | Assist, CompletionItem, CompletionItemKind, Documentation, FileSystemEdit, Fold, FoldKind, |
5 | FunctionSignature, Highlight, HighlightModifier, HighlightTag, HighlightedRange, Indel, | 5 | FunctionSignature, Highlight, HighlightModifier, HighlightTag, HighlightedRange, Indel, |
6 | InlayHint, InlayKind, InsertTextFormat, LineIndex, NavigationTarget, ReferenceAccess, | 6 | InlayHint, InlayKind, InsertTextFormat, LineIndex, NavigationTarget, ReferenceAccess, |
7 | ResolvedAssist, Severity, SourceChange, SourceFileEdit, TextEdit, | 7 | ResolvedAssist, Runnable, RunnableKind, Severity, SourceChange, SourceFileEdit, TextEdit, |
8 | }; | 8 | }; |
9 | use ra_syntax::{SyntaxKind, TextRange, TextSize}; | 9 | use ra_syntax::{SyntaxKind, TextRange, TextSize}; |
10 | use ra_vfs::LineEndings; | 10 | use ra_vfs::LineEndings; |
11 | 11 | ||
12 | use crate::{lsp_ext, semantic_tokens, world::WorldSnapshot, Result}; | 12 | use crate::{ |
13 | cargo_target_spec::CargoTargetSpec, lsp_ext, semantic_tokens, world::WorldSnapshot, Result, | ||
14 | }; | ||
13 | 15 | ||
14 | pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position { | 16 | pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position { |
15 | let line_col = line_index.line_col(offset); | 17 | let line_col = line_index.line_col(offset); |
@@ -658,3 +660,35 @@ pub(crate) fn resolved_code_action( | |||
658 | }; | 660 | }; |
659 | Ok(res) | 661 | Ok(res) |
660 | } | 662 | } |
663 | |||
664 | pub(crate) fn runnable( | ||
665 | world: &WorldSnapshot, | ||
666 | file_id: FileId, | ||
667 | runnable: Runnable, | ||
668 | ) -> Result<lsp_ext::Runnable> { | ||
669 | let spec = CargoTargetSpec::for_file(world, file_id)?; | ||
670 | let target = spec.as_ref().map(|s| s.target.clone()); | ||
671 | let (cargo_args, executable_args) = | ||
672 | CargoTargetSpec::runnable_args(spec, &runnable.kind, &runnable.cfg_exprs)?; | ||
673 | let label = match &runnable.kind { | ||
674 | RunnableKind::Test { test_id, .. } => format!("test {}", test_id), | ||
675 | RunnableKind::TestMod { path } => format!("test-mod {}", path), | ||
676 | RunnableKind::Bench { test_id } => format!("bench {}", test_id), | ||
677 | RunnableKind::DocTest { test_id, .. } => format!("doctest {}", test_id), | ||
678 | RunnableKind::Bin => { | ||
679 | target.map_or_else(|| "run binary".to_string(), |t| format!("run {}", t)) | ||
680 | } | ||
681 | }; | ||
682 | let location = location_link(world, None, runnable.nav)?; | ||
683 | |||
684 | Ok(lsp_ext::Runnable { | ||
685 | label, | ||
686 | location: Some(location), | ||
687 | kind: lsp_ext::RunnableKind::Cargo, | ||
688 | args: lsp_ext::CargoRunnable { | ||
689 | workspace_root: world.workspace_root_for(file_id).map(|root| root.to_owned()), | ||
690 | cargo_args, | ||
691 | executable_args, | ||
692 | }, | ||
693 | }) | ||
694 | } | ||
diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs index 8b473ff74..e18f973b8 100644 --- a/crates/rust-analyzer/tests/heavy_tests/main.rs +++ b/crates/rust-analyzer/tests/heavy_tests/main.rs | |||
@@ -76,30 +76,33 @@ fn foo() { | |||
76 | server.request::<Runnables>( | 76 | server.request::<Runnables>( |
77 | RunnablesParams { text_document: server.doc_id("lib.rs"), position: None }, | 77 | RunnablesParams { text_document: server.doc_id("lib.rs"), position: None }, |
78 | json!([ | 78 | json!([ |
79 | { | 79 | { |
80 | "args": [ "test" ], | 80 | "args": { |
81 | "extraArgs": [ "foo", "--nocapture" ], | 81 | "cargoArgs": ["test"], |
82 | "kind": "cargo", | 82 | "executableArgs": ["foo", "--nocapture"], |
83 | "env": { "RUST_BACKTRACE": "short" }, | 83 | }, |
84 | "cwd": null, | 84 | "kind": "cargo", |
85 | "label": "test foo", | 85 | "label": "test foo", |
86 | "range": { | 86 | "location": { |
87 | "end": { "character": 1, "line": 2 }, | 87 | "targetRange": { |
88 | "start": { "character": 0, "line": 0 } | 88 | "end": { "character": 1, "line": 2 }, |
89 | } | 89 | "start": { "character": 0, "line": 0 } |
90 | }, | 90 | }, |
91 | { | 91 | "targetSelectionRange": { |
92 | "args": ["check", "--workspace"], | 92 | "end": { "character": 6, "line": 1 }, |
93 | "extraArgs": [], | 93 | "start": { "character": 3, "line": 1 } |
94 | "kind": "cargo", | 94 | }, |
95 | "env": {}, | 95 | "targetUri": "file:///[..]/lib.rs" |
96 | "cwd": null, | 96 | } |
97 | "label": "cargo check --workspace", | 97 | }, |
98 | "range": { | 98 | { |
99 | "end": { "character": 0, "line": 0 }, | 99 | "args": { |
100 | "start": { "character": 0, "line": 0 } | 100 | "cargoArgs": ["check", "--workspace"], |
101 | "executableArgs": [], | ||
102 | }, | ||
103 | "kind": "cargo", | ||
104 | "label": "cargo check --workspace" | ||
101 | } | 105 | } |
102 | } | ||
103 | ]), | 106 | ]), |
104 | ); | 107 | ); |
105 | } | 108 | } |
@@ -138,42 +141,44 @@ fn main() {} | |||
138 | server.request::<Runnables>( | 141 | server.request::<Runnables>( |
139 | RunnablesParams { text_document: server.doc_id("foo/tests/spam.rs"), position: None }, | 142 | RunnablesParams { text_document: server.doc_id("foo/tests/spam.rs"), position: None }, |
140 | json!([ | 143 | json!([ |
141 | { | 144 | { |
142 | "args": [ "test", "--package", "foo", "--test", "spam" ], | 145 | "args": { |
143 | "extraArgs": [ "test_eggs", "--exact", "--nocapture" ], | 146 | "cargoArgs": ["test", "--package", "foo", "--test", "spam"], |
144 | "kind": "cargo", | 147 | "executableArgs": ["test_eggs", "--exact", "--nocapture"], |
145 | "env": { "RUST_BACKTRACE": "short" }, | 148 | "workspaceRoot": server.path().join("foo") |
146 | "label": "test test_eggs", | ||
147 | "range": { | ||
148 | "end": { "character": 17, "line": 1 }, | ||
149 | "start": { "character": 0, "line": 0 } | ||
150 | }, | ||
151 | "cwd": server.path().join("foo") | ||
152 | }, | 149 | }, |
153 | { | 150 | "kind": "cargo", |
154 | "args": [ "check", "--package", "foo" ], | 151 | "label": "test test_eggs", |
155 | "extraArgs": [], | 152 | "location": { |
156 | "kind": "cargo", | 153 | "targetRange": { |
157 | "env": {}, | 154 | "end": { "character": 17, "line": 1 }, |
158 | "label": "cargo check -p foo", | ||
159 | "range": { | ||
160 | "end": { "character": 0, "line": 0 }, | ||
161 | "start": { "character": 0, "line": 0 } | 155 | "start": { "character": 0, "line": 0 } |
162 | }, | 156 | }, |
163 | "cwd": server.path().join("foo") | 157 | "targetSelectionRange": { |
164 | }, | 158 | "end": { "character": 12, "line": 1 }, |
165 | { | 159 | "start": { "character": 3, "line": 1 } |
166 | "args": [ "test", "--package", "foo" ], | ||
167 | "extraArgs": [], | ||
168 | "kind": "cargo", | ||
169 | "env": {}, | ||
170 | "label": "cargo test -p foo", | ||
171 | "range": { | ||
172 | "end": { "character": 0, "line": 0 }, | ||
173 | "start": { "character": 0, "line": 0 } | ||
174 | }, | 160 | }, |
175 | "cwd": server.path().join("foo") | 161 | "targetUri": "file:///[..]/tests/spam.rs" |
176 | } | 162 | } |
163 | }, | ||
164 | { | ||
165 | "args": { | ||
166 | "cargoArgs": ["check", "--package", "foo"], | ||
167 | "executableArgs": [], | ||
168 | "workspaceRoot": server.path().join("foo") | ||
169 | }, | ||
170 | "kind": "cargo", | ||
171 | "label": "cargo check -p foo" | ||
172 | }, | ||
173 | { | ||
174 | "args": { | ||
175 | "cargoArgs": ["test", "--package", "foo"], | ||
176 | "executableArgs": [], | ||
177 | "workspaceRoot": server.path().join("foo") | ||
178 | }, | ||
179 | "kind": "cargo", | ||
180 | "label": "cargo test -p foo" | ||
181 | } | ||
177 | ]), | 182 | ]), |
178 | ); | 183 | ); |
179 | } | 184 | } |
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index b7237ee90..647cf6107 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md | |||
@@ -311,6 +311,50 @@ Moreover, it would be cool if editors didn't need to implement even basic langua | |||
311 | This is how `SelectionRange` request works. | 311 | This is how `SelectionRange` request works. |
312 | * Alternatively, should we perhaps flag certain `SelectionRange`s as being brace pairs? | 312 | * Alternatively, should we perhaps flag certain `SelectionRange`s as being brace pairs? |
313 | 313 | ||
314 | ## Runnables | ||
315 | |||
316 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/944 | ||
317 | |||
318 | **Server Capability:** `{ "runnables": { "kinds": string[] } }` | ||
319 | |||
320 | This request is send from client to server to get the list of things that can be run (tests, binaries, `cargo check -p`). | ||
321 | |||
322 | **Method:** `experimental/runnables` | ||
323 | |||
324 | **Request:** | ||
325 | |||
326 | ```typescript | ||
327 | interface RunnablesParams { | ||
328 | textDocument: TextDocumentIdentifier; | ||
329 | /// If null, compute runnables for the whole file. | ||
330 | position?: Position; | ||
331 | } | ||
332 | ``` | ||
333 | |||
334 | **Response:** `Runnable[]` | ||
335 | |||
336 | ```typescript | ||
337 | interface Runnable { | ||
338 | label: string; | ||
339 | /// If this Runnable is associated with a specific function/module, etc, the location of this item | ||
340 | location?: LocationLink; | ||
341 | /// Running things is necessary technology specific, `kind` needs to be advertised via server capabilities, | ||
342 | // the type of `args` is specific to `kind`. The actual running is handled by the client. | ||
343 | kind: string; | ||
344 | args: any; | ||
345 | } | ||
346 | ``` | ||
347 | |||
348 | rust-analyzer supports only one `kind`, `"cargo"`. The `args` for `"cargo"` look like this: | ||
349 | |||
350 | ```typescript | ||
351 | { | ||
352 | workspaceRoot?: string; | ||
353 | cargoArgs: string[]; | ||
354 | executableArgs: string[]; | ||
355 | } | ||
356 | ``` | ||
357 | |||
314 | ## Analyzer Status | 358 | ## Analyzer Status |
315 | 359 | ||
316 | **Method:** `rust-analyzer/analyzerStatus` | 360 | **Method:** `rust-analyzer/analyzerStatus` |
@@ -399,39 +443,3 @@ interface InlayHint { | |||
399 | label: string, | 443 | label: string, |
400 | } | 444 | } |
401 | ``` | 445 | ``` |
402 | |||
403 | ## Runnables | ||
404 | |||
405 | **Method:** `rust-analyzer/runnables` | ||
406 | |||
407 | This request is send from client to server to get the list of things that can be run (tests, binaries, `cargo check -p`). | ||
408 | Note that we plan to move this request to `experimental/runnables`, as it is not really Rust-specific, but the current API is not necessary the right one. | ||
409 | Upstream issue: https://github.com/microsoft/language-server-protocol/issues/944 | ||
410 | |||
411 | **Request:** | ||
412 | |||
413 | ```typescript | ||
414 | interface RunnablesParams { | ||
415 | textDocument: TextDocumentIdentifier; | ||
416 | /// If null, compute runnables for the whole file. | ||
417 | position?: Position; | ||
418 | } | ||
419 | ``` | ||
420 | |||
421 | **Response:** `Runnable[]` | ||
422 | |||
423 | ```typescript | ||
424 | interface Runnable { | ||
425 | /// The range this runnable is applicable for. | ||
426 | range: lc.Range; | ||
427 | /// The label to show in the UI. | ||
428 | label: string; | ||
429 | /// The following fields describe a process to spawn. | ||
430 | kind: "cargo" | "rustc" | "rustup"; | ||
431 | args: string[]; | ||
432 | /// Args for cargo after `--`. | ||
433 | extraArgs: string[]; | ||
434 | env: { [key: string]: string }; | ||
435 | cwd: string | null; | ||
436 | } | ||
437 | ``` | ||
diff --git a/editors/code/package.json b/editors/code/package.json index 75dbafc05..d8f4287fd 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -238,7 +238,7 @@ | |||
238 | }, | 238 | }, |
239 | "rust-analyzer.cargo.allFeatures": { | 239 | "rust-analyzer.cargo.allFeatures": { |
240 | "type": "boolean", | 240 | "type": "boolean", |
241 | "default": true, | 241 | "default": false, |
242 | "description": "Activate all available features" | 242 | "description": "Activate all available features" |
243 | }, | 243 | }, |
244 | "rust-analyzer.cargo.features": { | 244 | "rust-analyzer.cargo.features": { |
@@ -319,7 +319,7 @@ | |||
319 | }, | 319 | }, |
320 | "rust-analyzer.checkOnSave.allFeatures": { | 320 | "rust-analyzer.checkOnSave.allFeatures": { |
321 | "type": "boolean", | 321 | "type": "boolean", |
322 | "default": true, | 322 | "default": false, |
323 | "markdownDescription": "Check with all features (will be passed as `--all-features`)" | 323 | "markdownDescription": "Check with all features (will be passed as `--all-features`)" |
324 | }, | 324 | }, |
325 | "rust-analyzer.inlayHints.enable": { | 325 | "rust-analyzer.inlayHints.enable": { |
diff --git a/editors/code/src/debug.ts b/editors/code/src/debug.ts index 1e421d407..a0c9b3ab2 100644 --- a/editors/code/src/debug.ts +++ b/editors/code/src/debug.ts | |||
@@ -114,8 +114,8 @@ async function getDebugConfiguration(ctx: Ctx, runnable: ra.Runnable): Promise<v | |||
114 | } | 114 | } |
115 | 115 | ||
116 | async function getDebugExecutable(runnable: ra.Runnable): Promise<string> { | 116 | async function getDebugExecutable(runnable: ra.Runnable): Promise<string> { |
117 | const cargo = new Cargo(runnable.cwd || '.', debugOutput); | 117 | const cargo = new Cargo(runnable.args.workspaceRoot || '.', debugOutput); |
118 | const executable = await cargo.executableFromArgs(runnable.args); | 118 | const executable = await cargo.executableFromArgs(runnable.args.cargoArgs); |
119 | 119 | ||
120 | // if we are here, there were no compilation errors. | 120 | // if we are here, there were no compilation errors. |
121 | return executable; | 121 | return executable; |
@@ -127,8 +127,8 @@ function getLldbDebugConfig(runnable: ra.Runnable, executable: string, sourceFil | |||
127 | request: "launch", | 127 | request: "launch", |
128 | name: runnable.label, | 128 | name: runnable.label, |
129 | program: executable, | 129 | program: executable, |
130 | args: runnable.extraArgs, | 130 | args: runnable.args.executableArgs, |
131 | cwd: runnable.cwd, | 131 | cwd: runnable.args.workspaceRoot, |
132 | sourceMap: sourceFileMap, | 132 | sourceMap: sourceFileMap, |
133 | sourceLanguages: ["rust"] | 133 | sourceLanguages: ["rust"] |
134 | }; | 134 | }; |
@@ -140,8 +140,8 @@ function getCppvsDebugConfig(runnable: ra.Runnable, executable: string, sourceFi | |||
140 | request: "launch", | 140 | request: "launch", |
141 | name: runnable.label, | 141 | name: runnable.label, |
142 | program: executable, | 142 | program: executable, |
143 | args: runnable.extraArgs, | 143 | args: runnable.args.executableArgs, |
144 | cwd: runnable.cwd, | 144 | cwd: runnable.args.workspaceRoot, |
145 | sourceFileMap: sourceFileMap, | 145 | sourceFileMap: sourceFileMap, |
146 | }; | 146 | }; |
147 | } | 147 | } |
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts index f881bae47..35d73ce31 100644 --- a/editors/code/src/lsp_ext.ts +++ b/editors/code/src/lsp_ext.ts | |||
@@ -53,18 +53,17 @@ export interface RunnablesParams { | |||
53 | position: lc.Position | null; | 53 | position: lc.Position | null; |
54 | } | 54 | } |
55 | 55 | ||
56 | export type RunnableKind = "cargo" | "rustc" | "rustup"; | ||
57 | |||
58 | export interface Runnable { | 56 | export interface Runnable { |
59 | range: lc.Range; | ||
60 | label: string; | 57 | label: string; |
61 | kind: RunnableKind; | 58 | location?: lc.LocationLink; |
62 | args: string[]; | 59 | kind: "cargo"; |
63 | extraArgs: string[]; | 60 | args: { |
64 | env: { [key: string]: string }; | 61 | workspaceRoot?: string; |
65 | cwd: string | null; | 62 | cargoArgs: string[]; |
63 | executableArgs: string[]; | ||
64 | }; | ||
66 | } | 65 | } |
67 | export const runnables = new lc.RequestType<RunnablesParams, Runnable[], void>("rust-analyzer/runnables"); | 66 | export const runnables = new lc.RequestType<RunnablesParams, Runnable[], void>("experimental/runnables"); |
68 | 67 | ||
69 | export type InlayHint = InlayHint.TypeHint | InlayHint.ParamHint | InlayHint.ChainingHint; | 68 | export type InlayHint = InlayHint.TypeHint | InlayHint.ParamHint | InlayHint.ChainingHint; |
70 | 69 | ||
diff --git a/editors/code/src/run.ts b/editors/code/src/run.ts index 5fc4f8e41..5c790741f 100644 --- a/editors/code/src/run.ts +++ b/editors/code/src/run.ts | |||
@@ -103,18 +103,27 @@ interface CargoTaskDefinition extends vscode.TaskDefinition { | |||
103 | env?: { [key: string]: string }; | 103 | env?: { [key: string]: string }; |
104 | } | 104 | } |
105 | 105 | ||
106 | export function createTask(spec: ra.Runnable): vscode.Task { | 106 | export function createTask(runnable: ra.Runnable): vscode.Task { |
107 | const TASK_SOURCE = 'Rust'; | 107 | const TASK_SOURCE = 'Rust'; |
108 | |||
109 | let command; | ||
110 | switch (runnable.kind) { | ||
111 | case "cargo": command = toolchain.getPathForExecutable("cargo"); | ||
112 | } | ||
113 | const args = runnable.args.cargoArgs; | ||
114 | if (runnable.args.executableArgs.length > 0) { | ||
115 | args.push('--', ...runnable.args.executableArgs); | ||
116 | } | ||
108 | const definition: CargoTaskDefinition = { | 117 | const definition: CargoTaskDefinition = { |
109 | type: 'cargo', | 118 | type: 'cargo', |
110 | label: spec.label, | 119 | label: runnable.label, |
111 | command: toolchain.getPathForExecutable(spec.kind), | 120 | command, |
112 | args: spec.extraArgs ? [...spec.args, '--', ...spec.extraArgs] : spec.args, | 121 | args, |
113 | env: Object.assign({}, process.env, spec.env), | 122 | env: Object.assign({}, process.env as { [key: string]: string }, { "RUST_BACKTRACE": "short" }), |
114 | }; | 123 | }; |
115 | 124 | ||
116 | const execOption: vscode.ShellExecutionOptions = { | 125 | const execOption: vscode.ShellExecutionOptions = { |
117 | cwd: spec.cwd || '.', | 126 | cwd: runnable.args.workspaceRoot || '.', |
118 | env: definition.env, | 127 | env: definition.env, |
119 | }; | 128 | }; |
120 | const exec = new vscode.ShellExecution( | 129 | const exec = new vscode.ShellExecution( |