diff options
-rw-r--r-- | crates/ra_ide/src/display/navigation_target.rs | 15 | ||||
-rw-r--r-- | crates/ra_ide/src/goto_definition.rs | 169 | ||||
-rw-r--r-- | crates/test_utils/src/lib.rs | 4 | ||||
-rw-r--r-- | docs/user/README.md | 29 | ||||
-rw-r--r-- | xtask/src/lib.rs | 1 |
5 files changed, 142 insertions, 76 deletions
diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs index 6a6b49afd..b9ae67828 100644 --- a/crates/ra_ide/src/display/navigation_target.rs +++ b/crates/ra_ide/src/display/navigation_target.rs | |||
@@ -328,22 +328,23 @@ impl ToNav for hir::AssocItem { | |||
328 | impl ToNav for hir::Local { | 328 | impl ToNav for hir::Local { |
329 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 329 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { |
330 | let src = self.source(db); | 330 | let src = self.source(db); |
331 | let (full_range, focus_range) = match src.value { | 331 | let node = match &src.value { |
332 | Either::Left(it) => { | 332 | Either::Left(bind_pat) => { |
333 | (it.syntax().text_range(), it.name().map(|it| it.syntax().text_range())) | 333 | bind_pat.name().map_or_else(|| bind_pat.syntax().clone(), |it| it.syntax().clone()) |
334 | } | 334 | } |
335 | Either::Right(it) => (it.syntax().text_range(), Some(it.self_kw_token().text_range())), | 335 | Either::Right(it) => it.syntax().clone(), |
336 | }; | 336 | }; |
337 | let full_range = original_range(db, src.with_value(&node)); | ||
337 | let name = match self.name(db) { | 338 | let name = match self.name(db) { |
338 | Some(it) => it.to_string().into(), | 339 | Some(it) => it.to_string().into(), |
339 | None => "".into(), | 340 | None => "".into(), |
340 | }; | 341 | }; |
341 | NavigationTarget { | 342 | NavigationTarget { |
342 | file_id: src.file_id.original_file(db), | 343 | file_id: full_range.file_id, |
343 | name, | 344 | name, |
344 | kind: BIND_PAT, | 345 | kind: BIND_PAT, |
345 | full_range, | 346 | full_range: full_range.range, |
346 | focus_range, | 347 | focus_range: None, |
347 | container_name: None, | 348 | container_name: None, |
348 | description: None, | 349 | description: None, |
349 | docs: None, | 350 | docs: None, |
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs index bee8e9df2..184555792 100644 --- a/crates/ra_ide/src/goto_definition.rs +++ b/crates/ra_ide/src/goto_definition.rs | |||
@@ -225,30 +225,35 @@ mod tests { | |||
225 | 225 | ||
226 | use crate::mock_analysis::analysis_and_position; | 226 | use crate::mock_analysis::analysis_and_position; |
227 | 227 | ||
228 | fn check_goto(fixture: &str, expected: &str) { | 228 | fn check_goto(fixture: &str, expected: &str, expected_range: &str) { |
229 | let (analysis, pos) = analysis_and_position(fixture); | 229 | let (analysis, pos) = analysis_and_position(fixture); |
230 | 230 | ||
231 | let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info; | 231 | let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info; |
232 | assert_eq!(navs.len(), 1); | 232 | assert_eq!(navs.len(), 1); |
233 | let nav = navs.pop().unwrap(); | ||
234 | nav.assert_match(expected); | ||
235 | } | ||
236 | 233 | ||
237 | fn check_goto_with_range_content(fixture: &str, expected: &str, expected_range: &str) { | ||
238 | let (analysis, pos) = analysis_and_position(fixture); | ||
239 | |||
240 | let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info; | ||
241 | assert_eq!(navs.len(), 1); | ||
242 | let nav = navs.pop().unwrap(); | 234 | let nav = navs.pop().unwrap(); |
243 | let file_text = analysis.file_text(pos.file_id).unwrap(); | 235 | let file_text = analysis.file_text(nav.file_id()).unwrap(); |
244 | 236 | ||
245 | let actual_full_range = &file_text[nav.full_range()]; | 237 | let mut actual = file_text[nav.full_range()].to_string(); |
246 | let actual_range = &file_text[nav.range()]; | 238 | if let Some(focus) = nav.focus_range() { |
239 | actual += "|"; | ||
240 | actual += &file_text[focus]; | ||
241 | } | ||
242 | |||
243 | if !expected_range.contains("...") { | ||
244 | test_utils::assert_eq_text!(&actual, expected_range); | ||
245 | } else { | ||
246 | let mut parts = expected_range.split("..."); | ||
247 | let prefix = parts.next().unwrap(); | ||
248 | let suffix = parts.next().unwrap(); | ||
249 | assert!( | ||
250 | actual.starts_with(prefix) && actual.ends_with(suffix), | ||
251 | "\nExpected: {}\n Actual: {}\n", | ||
252 | expected_range, | ||
253 | actual | ||
254 | ); | ||
255 | } | ||
247 | 256 | ||
248 | test_utils::assert_eq_text!( | ||
249 | &format!("{}|{}", actual_full_range, actual_range), | ||
250 | expected_range | ||
251 | ); | ||
252 | nav.assert_match(expected); | 257 | nav.assert_match(expected); |
253 | } | 258 | } |
254 | 259 | ||
@@ -261,6 +266,7 @@ mod tests { | |||
261 | enum E { X(Foo<|>) } | 266 | enum E { X(Foo<|>) } |
262 | ", | 267 | ", |
263 | "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)", | 268 | "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)", |
269 | "struct Foo;|Foo", | ||
264 | ); | 270 | ); |
265 | } | 271 | } |
266 | 272 | ||
@@ -273,6 +279,7 @@ mod tests { | |||
273 | enum E { X(<|>Foo) } | 279 | enum E { X(<|>Foo) } |
274 | ", | 280 | ", |
275 | "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)", | 281 | "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)", |
282 | "struct Foo;|Foo", | ||
276 | ); | 283 | ); |
277 | } | 284 | } |
278 | 285 | ||
@@ -285,12 +292,15 @@ mod tests { | |||
285 | mod a; | 292 | mod a; |
286 | mod b; | 293 | mod b; |
287 | enum E { X(Foo<|>) } | 294 | enum E { X(Foo<|>) } |
295 | |||
288 | //- /a.rs | 296 | //- /a.rs |
289 | struct Foo; | 297 | struct Foo; |
298 | |||
290 | //- /b.rs | 299 | //- /b.rs |
291 | struct Foo; | 300 | struct Foo; |
292 | ", | 301 | ", |
293 | "Foo STRUCT_DEF FileId(2) [0; 11) [7; 10)", | 302 | "Foo STRUCT_DEF FileId(2) [0; 11) [7; 10)", |
303 | "struct Foo;|Foo", | ||
294 | ); | 304 | ); |
295 | } | 305 | } |
296 | 306 | ||
@@ -300,20 +310,24 @@ mod tests { | |||
300 | " | 310 | " |
301 | //- /lib.rs | 311 | //- /lib.rs |
302 | mod <|>foo; | 312 | mod <|>foo; |
313 | |||
303 | //- /foo.rs | 314 | //- /foo.rs |
304 | // empty | 315 | // empty |
305 | ", | 316 | ", |
306 | "foo SOURCE_FILE FileId(2) [0; 10)", | 317 | "foo SOURCE_FILE FileId(2) [0; 10)", |
318 | "// empty\n\n", | ||
307 | ); | 319 | ); |
308 | 320 | ||
309 | check_goto( | 321 | check_goto( |
310 | " | 322 | " |
311 | //- /lib.rs | 323 | //- /lib.rs |
312 | mod <|>foo; | 324 | mod <|>foo; |
325 | |||
313 | //- /foo/mod.rs | 326 | //- /foo/mod.rs |
314 | // empty | 327 | // empty |
315 | ", | 328 | ", |
316 | "foo SOURCE_FILE FileId(2) [0; 10)", | 329 | "foo SOURCE_FILE FileId(2) [0; 10)", |
330 | "// empty\n\n", | ||
317 | ); | 331 | ); |
318 | } | 332 | } |
319 | 333 | ||
@@ -323,17 +337,14 @@ mod tests { | |||
323 | check_goto( | 337 | check_goto( |
324 | " | 338 | " |
325 | //- /lib.rs | 339 | //- /lib.rs |
326 | macro_rules! foo { | 340 | macro_rules! foo { () => { () } } |
327 | () => { | ||
328 | {} | ||
329 | }; | ||
330 | } | ||
331 | 341 | ||
332 | fn bar() { | 342 | fn bar() { |
333 | <|>foo!(); | 343 | <|>foo!(); |
334 | } | 344 | } |
335 | ", | 345 | ", |
336 | "foo MACRO_CALL FileId(1) [0; 50) [13; 16)", | 346 | "foo MACRO_CALL FileId(1) [0; 33) [13; 16)", |
347 | "macro_rules! foo { () => { () } }|foo", | ||
337 | ); | 348 | ); |
338 | } | 349 | } |
339 | 350 | ||
@@ -350,13 +361,10 @@ mod tests { | |||
350 | 361 | ||
351 | //- /foo/lib.rs | 362 | //- /foo/lib.rs |
352 | #[macro_export] | 363 | #[macro_export] |
353 | macro_rules! foo { | 364 | macro_rules! foo { () => { () } } |
354 | () => { | ||
355 | {} | ||
356 | }; | ||
357 | } | ||
358 | ", | 365 | ", |
359 | "foo MACRO_CALL FileId(2) [0; 66) [29; 32)", | 366 | "foo MACRO_CALL FileId(2) [0; 49) [29; 32)", |
367 | "#[macro_export]\nmacro_rules! foo { () => { () } }|foo", | ||
360 | ); | 368 | ); |
361 | } | 369 | } |
362 | 370 | ||
@@ -369,19 +377,16 @@ mod tests { | |||
369 | 377 | ||
370 | //- /foo/lib.rs | 378 | //- /foo/lib.rs |
371 | #[macro_export] | 379 | #[macro_export] |
372 | macro_rules! foo { | 380 | macro_rules! foo { () => { () } } |
373 | () => { | ||
374 | {} | ||
375 | }; | ||
376 | } | ||
377 | ", | 381 | ", |
378 | "foo MACRO_CALL FileId(2) [0; 66) [29; 32)", | 382 | "foo MACRO_CALL FileId(2) [0; 49) [29; 32)", |
383 | "#[macro_export]\nmacro_rules! foo { () => { () } }|foo", | ||
379 | ); | 384 | ); |
380 | } | 385 | } |
381 | 386 | ||
382 | #[test] | 387 | #[test] |
383 | fn goto_definition_works_for_macro_defined_fn_with_arg() { | 388 | fn goto_definition_works_for_macro_defined_fn_with_arg() { |
384 | check_goto_with_range_content( | 389 | check_goto( |
385 | " | 390 | " |
386 | //- /lib.rs | 391 | //- /lib.rs |
387 | macro_rules! define_fn { | 392 | macro_rules! define_fn { |
@@ -401,7 +406,7 @@ mod tests { | |||
401 | 406 | ||
402 | #[test] | 407 | #[test] |
403 | fn goto_definition_works_for_macro_defined_fn_no_arg() { | 408 | fn goto_definition_works_for_macro_defined_fn_no_arg() { |
404 | check_goto_with_range_content( | 409 | check_goto( |
405 | " | 410 | " |
406 | //- /lib.rs | 411 | //- /lib.rs |
407 | macro_rules! define_fn { | 412 | macro_rules! define_fn { |
@@ -427,14 +432,15 @@ mod tests { | |||
427 | //- /lib.rs | 432 | //- /lib.rs |
428 | struct Foo; | 433 | struct Foo; |
429 | impl Foo { | 434 | impl Foo { |
430 | fn frobnicate(&self) { } | 435 | fn frobnicate(&self) { } |
431 | } | 436 | } |
432 | 437 | ||
433 | fn bar(foo: &Foo) { | 438 | fn bar(foo: &Foo) { |
434 | foo.frobnicate<|>(); | 439 | foo.frobnicate<|>(); |
435 | } | 440 | } |
436 | ", | 441 | ", |
437 | "frobnicate FN_DEF FileId(1) [27; 52) [30; 40)", | 442 | "frobnicate FN_DEF FileId(1) [27; 51) [30; 40)", |
443 | "fn frobnicate(&self) { }|frobnicate", | ||
438 | ); | 444 | ); |
439 | } | 445 | } |
440 | 446 | ||
@@ -453,6 +459,7 @@ mod tests { | |||
453 | } | 459 | } |
454 | ", | 460 | ", |
455 | "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)", | 461 | "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)", |
462 | "spam: u32|spam", | ||
456 | ); | 463 | ); |
457 | } | 464 | } |
458 | 465 | ||
@@ -473,6 +480,7 @@ mod tests { | |||
473 | } | 480 | } |
474 | ", | 481 | ", |
475 | "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)", | 482 | "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)", |
483 | "spam: u32|spam", | ||
476 | ); | 484 | ); |
477 | } | 485 | } |
478 | 486 | ||
@@ -489,6 +497,7 @@ mod tests { | |||
489 | } | 497 | } |
490 | ", | 498 | ", |
491 | "TUPLE_FIELD_DEF FileId(1) [11; 14)", | 499 | "TUPLE_FIELD_DEF FileId(1) [11; 14)", |
500 | "u32", | ||
492 | ); | 501 | ); |
493 | } | 502 | } |
494 | 503 | ||
@@ -499,14 +508,15 @@ mod tests { | |||
499 | //- /lib.rs | 508 | //- /lib.rs |
500 | struct Foo; | 509 | struct Foo; |
501 | impl Foo { | 510 | impl Foo { |
502 | fn frobnicate() { } | 511 | fn frobnicate() { } |
503 | } | 512 | } |
504 | 513 | ||
505 | fn bar(foo: &Foo) { | 514 | fn bar(foo: &Foo) { |
506 | Foo::frobnicate<|>(); | 515 | Foo::frobnicate<|>(); |
507 | } | 516 | } |
508 | ", | 517 | ", |
509 | "frobnicate FN_DEF FileId(1) [27; 47) [30; 40)", | 518 | "frobnicate FN_DEF FileId(1) [27; 46) [30; 40)", |
519 | "fn frobnicate() { }|frobnicate", | ||
510 | ); | 520 | ); |
511 | } | 521 | } |
512 | 522 | ||
@@ -524,6 +534,7 @@ mod tests { | |||
524 | } | 534 | } |
525 | ", | 535 | ", |
526 | "frobnicate FN_DEF FileId(1) [16; 32) [19; 29)", | 536 | "frobnicate FN_DEF FileId(1) [16; 32) [19; 29)", |
537 | "fn frobnicate();|frobnicate", | ||
527 | ); | 538 | ); |
528 | } | 539 | } |
529 | 540 | ||
@@ -543,6 +554,7 @@ mod tests { | |||
543 | } | 554 | } |
544 | ", | 555 | ", |
545 | "frobnicate FN_DEF FileId(1) [30; 46) [33; 43)", | 556 | "frobnicate FN_DEF FileId(1) [30; 46) [33; 43)", |
557 | "fn frobnicate();|frobnicate", | ||
546 | ); | 558 | ); |
547 | } | 559 | } |
548 | 560 | ||
@@ -559,6 +571,7 @@ mod tests { | |||
559 | } | 571 | } |
560 | ", | 572 | ", |
561 | "impl IMPL_BLOCK FileId(1) [12; 73)", | 573 | "impl IMPL_BLOCK FileId(1) [12; 73)", |
574 | "impl Foo {...}", | ||
562 | ); | 575 | ); |
563 | 576 | ||
564 | check_goto( | 577 | check_goto( |
@@ -572,6 +585,7 @@ mod tests { | |||
572 | } | 585 | } |
573 | ", | 586 | ", |
574 | "impl IMPL_BLOCK FileId(1) [12; 73)", | 587 | "impl IMPL_BLOCK FileId(1) [12; 73)", |
588 | "impl Foo {...}", | ||
575 | ); | 589 | ); |
576 | 590 | ||
577 | check_goto( | 591 | check_goto( |
@@ -585,6 +599,7 @@ mod tests { | |||
585 | } | 599 | } |
586 | ", | 600 | ", |
587 | "impl IMPL_BLOCK FileId(1) [15; 75)", | 601 | "impl IMPL_BLOCK FileId(1) [15; 75)", |
602 | "impl Foo {...}", | ||
588 | ); | 603 | ); |
589 | 604 | ||
590 | check_goto( | 605 | check_goto( |
@@ -597,6 +612,7 @@ mod tests { | |||
597 | } | 612 | } |
598 | ", | 613 | ", |
599 | "impl IMPL_BLOCK FileId(1) [15; 62)", | 614 | "impl IMPL_BLOCK FileId(1) [15; 62)", |
615 | "impl Foo {...}", | ||
600 | ); | 616 | ); |
601 | } | 617 | } |
602 | 618 | ||
@@ -616,6 +632,7 @@ mod tests { | |||
616 | } | 632 | } |
617 | ", | 633 | ", |
618 | "impl IMPL_BLOCK FileId(1) [49; 115)", | 634 | "impl IMPL_BLOCK FileId(1) [49; 115)", |
635 | "impl Make for Foo {...}", | ||
619 | ); | 636 | ); |
620 | 637 | ||
621 | check_goto( | 638 | check_goto( |
@@ -632,6 +649,7 @@ mod tests { | |||
632 | } | 649 | } |
633 | ", | 650 | ", |
634 | "impl IMPL_BLOCK FileId(1) [49; 115)", | 651 | "impl IMPL_BLOCK FileId(1) [49; 115)", |
652 | "impl Make for Foo {...}", | ||
635 | ); | 653 | ); |
636 | } | 654 | } |
637 | 655 | ||
@@ -643,6 +661,7 @@ mod tests { | |||
643 | struct Foo<|> { value: u32 } | 661 | struct Foo<|> { value: u32 } |
644 | ", | 662 | ", |
645 | "Foo STRUCT_DEF FileId(1) [0; 25) [7; 10)", | 663 | "Foo STRUCT_DEF FileId(1) [0; 25) [7; 10)", |
664 | "struct Foo { value: u32 }|Foo", | ||
646 | ); | 665 | ); |
647 | 666 | ||
648 | check_goto( | 667 | check_goto( |
@@ -653,15 +672,16 @@ mod tests { | |||
653 | } | 672 | } |
654 | "#, | 673 | "#, |
655 | "field RECORD_FIELD_DEF FileId(1) [17; 30) [17; 22)", | 674 | "field RECORD_FIELD_DEF FileId(1) [17; 30) [17; 22)", |
675 | "field: string|field", | ||
656 | ); | 676 | ); |
657 | 677 | ||
658 | check_goto( | 678 | check_goto( |
659 | " | 679 | " |
660 | //- /lib.rs | 680 | //- /lib.rs |
661 | fn foo_test<|>() { | 681 | fn foo_test<|>() { } |
662 | } | ||
663 | ", | 682 | ", |
664 | "foo_test FN_DEF FileId(1) [0; 17) [3; 11)", | 683 | "foo_test FN_DEF FileId(1) [0; 17) [3; 11)", |
684 | "fn foo_test() { }|foo_test", | ||
665 | ); | 685 | ); |
666 | 686 | ||
667 | check_goto( | 687 | check_goto( |
@@ -672,6 +692,7 @@ mod tests { | |||
672 | } | 692 | } |
673 | ", | 693 | ", |
674 | "Foo ENUM_DEF FileId(1) [0; 25) [5; 8)", | 694 | "Foo ENUM_DEF FileId(1) [0; 25) [5; 8)", |
695 | "enum Foo {...}|Foo", | ||
675 | ); | 696 | ); |
676 | 697 | ||
677 | check_goto( | 698 | check_goto( |
@@ -684,22 +705,25 @@ mod tests { | |||
684 | } | 705 | } |
685 | ", | 706 | ", |
686 | "Variant2 ENUM_VARIANT FileId(1) [29; 37) [29; 37)", | 707 | "Variant2 ENUM_VARIANT FileId(1) [29; 37) [29; 37)", |
708 | "Variant2|Variant2", | ||
687 | ); | 709 | ); |
688 | 710 | ||
689 | check_goto( | 711 | check_goto( |
690 | r#" | 712 | r#" |
691 | //- /lib.rs | 713 | //- /lib.rs |
692 | static inner<|>: &str = ""; | 714 | static INNER<|>: &str = ""; |
693 | "#, | 715 | "#, |
694 | "inner STATIC_DEF FileId(1) [0; 24) [7; 12)", | 716 | "INNER STATIC_DEF FileId(1) [0; 24) [7; 12)", |
717 | "static INNER: &str = \"\";|INNER", | ||
695 | ); | 718 | ); |
696 | 719 | ||
697 | check_goto( | 720 | check_goto( |
698 | r#" | 721 | r#" |
699 | //- /lib.rs | 722 | //- /lib.rs |
700 | const inner<|>: &str = ""; | 723 | const INNER<|>: &str = ""; |
701 | "#, | 724 | "#, |
702 | "inner CONST_DEF FileId(1) [0; 23) [6; 11)", | 725 | "INNER CONST_DEF FileId(1) [0; 23) [6; 11)", |
726 | "const INNER: &str = \"\";|INNER", | ||
703 | ); | 727 | ); |
704 | 728 | ||
705 | check_goto( | 729 | check_goto( |
@@ -708,24 +732,25 @@ mod tests { | |||
708 | type Thing<|> = Option<()>; | 732 | type Thing<|> = Option<()>; |
709 | "#, | 733 | "#, |
710 | "Thing TYPE_ALIAS_DEF FileId(1) [0; 24) [5; 10)", | 734 | "Thing TYPE_ALIAS_DEF FileId(1) [0; 24) [5; 10)", |
735 | "type Thing = Option<()>;|Thing", | ||
711 | ); | 736 | ); |
712 | 737 | ||
713 | check_goto( | 738 | check_goto( |
714 | r#" | 739 | r#" |
715 | //- /lib.rs | 740 | //- /lib.rs |
716 | trait Foo<|> { | 741 | trait Foo<|> { } |
717 | } | ||
718 | "#, | 742 | "#, |
719 | "Foo TRAIT_DEF FileId(1) [0; 13) [6; 9)", | 743 | "Foo TRAIT_DEF FileId(1) [0; 13) [6; 9)", |
744 | "trait Foo { }|Foo", | ||
720 | ); | 745 | ); |
721 | 746 | ||
722 | check_goto( | 747 | check_goto( |
723 | r#" | 748 | r#" |
724 | //- /lib.rs | 749 | //- /lib.rs |
725 | mod bar<|> { | 750 | mod bar<|> { } |
726 | } | ||
727 | "#, | 751 | "#, |
728 | "bar MODULE FileId(1) [0; 11) [4; 7)", | 752 | "bar MODULE FileId(1) [0; 11) [4; 7)", |
753 | "mod bar { }|bar", | ||
729 | ); | 754 | ); |
730 | } | 755 | } |
731 | 756 | ||
@@ -746,6 +771,7 @@ mod tests { | |||
746 | mod confuse_index { fn foo(); } | 771 | mod confuse_index { fn foo(); } |
747 | ", | 772 | ", |
748 | "foo FN_DEF FileId(1) [52; 63) [55; 58)", | 773 | "foo FN_DEF FileId(1) [52; 63) [55; 58)", |
774 | "fn foo() {}|foo", | ||
749 | ); | 775 | ); |
750 | } | 776 | } |
751 | 777 | ||
@@ -774,6 +800,7 @@ mod tests { | |||
774 | } | 800 | } |
775 | ", | 801 | ", |
776 | "foo FN_DEF FileId(1) [398; 415) [401; 404)", | 802 | "foo FN_DEF FileId(1) [398; 415) [401; 404)", |
803 | "fn foo() -> i8 {}|foo", | ||
777 | ); | 804 | ); |
778 | } | 805 | } |
779 | 806 | ||
@@ -787,6 +814,48 @@ mod tests { | |||
787 | } | 814 | } |
788 | ", | 815 | ", |
789 | "T TYPE_PARAM FileId(1) [11; 12)", | 816 | "T TYPE_PARAM FileId(1) [11; 12)", |
817 | "T", | ||
818 | ); | ||
819 | } | ||
820 | |||
821 | #[test] | ||
822 | fn goto_within_macro() { | ||
823 | check_goto( | ||
824 | " | ||
825 | //- /lib.rs | ||
826 | macro_rules! id { | ||
827 | ($($tt:tt)*) => ($($tt)*) | ||
828 | } | ||
829 | |||
830 | fn foo() { | ||
831 | let x = 1; | ||
832 | id!({ | ||
833 | let y = <|>x; | ||
834 | let z = y; | ||
835 | }); | ||
836 | } | ||
837 | ", | ||
838 | "x BIND_PAT FileId(1) [69; 70)", | ||
839 | "x", | ||
840 | ); | ||
841 | |||
842 | check_goto( | ||
843 | " | ||
844 | //- /lib.rs | ||
845 | macro_rules! id { | ||
846 | ($($tt:tt)*) => ($($tt)*) | ||
847 | } | ||
848 | |||
849 | fn foo() { | ||
850 | let x = 1; | ||
851 | id!({ | ||
852 | let y = x; | ||
853 | let z = <|>y; | ||
854 | }); | ||
855 | } | ||
856 | ", | ||
857 | "y BIND_PAT FileId(1) [98; 99)", | ||
858 | "y", | ||
790 | ); | 859 | ); |
791 | } | 860 | } |
792 | } | 861 | } |
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index 657ddf2a6..659f77b71 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs | |||
@@ -207,8 +207,8 @@ pub fn lines_match(expected: &str, actual: &str) -> bool { | |||
207 | // Let's not deal with / vs \ (windows...) | 207 | // Let's not deal with / vs \ (windows...) |
208 | // First replace backslash-escaped backslashes with forward slashes | 208 | // First replace backslash-escaped backslashes with forward slashes |
209 | // which can occur in, for example, JSON output | 209 | // which can occur in, for example, JSON output |
210 | let expected = expected.replace("\\\\", "/").replace("\\", "/"); | 210 | let expected = expected.replace(r"\\", "/").replace(r"\", "/"); |
211 | let mut actual: &str = &actual.replace("\\\\", "/").replace("\\", "/"); | 211 | let mut actual: &str = &actual.replace(r"\\", "/").replace(r"\", "/"); |
212 | for (i, part) in expected.split("[..]").enumerate() { | 212 | for (i, part) in expected.split("[..]").enumerate() { |
213 | match actual.find(part) { | 213 | match actual.find(part) { |
214 | Some(j) => { | 214 | Some(j) => { |
diff --git a/docs/user/README.md b/docs/user/README.md index 04c349342..9cdabfd42 100644 --- a/docs/user/README.md +++ b/docs/user/README.md | |||
@@ -135,37 +135,25 @@ to load path and require it in `init.el` | |||
135 | * (Optionally) bind commands like `rust-analyzer-join-lines`, `rust-analyzer-extend-selection` and `rust-analyzer-expand-macro` to keys, and enable `rust-analyzer-inlay-hints-mode` to get inline type hints | 135 | * (Optionally) bind commands like `rust-analyzer-join-lines`, `rust-analyzer-extend-selection` and `rust-analyzer-expand-macro` to keys, and enable `rust-analyzer-inlay-hints-mode` to get inline type hints |
136 | 136 | ||
137 | 137 | ||
138 | ## Vim and NeoVim | 138 | ## Vim and NeoVim (coc-rust-analyzer) |
139 | 139 | ||
140 | Neovim 0.5 has a built in language server. For a quick start configuration of | 140 | * Install coc.nvim by following the instructions at [coc.nvim][] (nodejs required) |
141 | rust-analyzer, use [neovim/nvim-lsp](https://github.com/neovim/nvim-lsp#rust_analyzer). | 141 | * Run `:CocInstall coc-rust-analyzer` to install [coc-rust-analyzer], this extension implements _most_ of the features supported in the VSCode extension: |
142 | Once `neovim/nvim-lsp` is installed, you can use `call nvim_lsp#setup("rust_analyzer", {})` | ||
143 | or `lua require'nvim_lsp'.rust_analyzer.setup({})` to quickly get set up. | ||
144 | |||
145 | * Install coc.nvim by following the instructions at [coc.nvim] | ||
146 | - You will need nodejs installed. | ||
147 | - You may want to include some of the sample vim configurations [from here][coc-vim-conf] | ||
148 | - Note that if you use a plugin manager other than `vim-plug`, you may need to manually | ||
149 | checkout the `release` branch wherever your plugin manager cloned it. Otherwise you will | ||
150 | get errors about a missing javascript file. | ||
151 | * Run `:CocInstall coc-rust-analyzer` to install [coc-rust-analyzer], this extension implemented _most_ of the features supported in the VSCode extension: | ||
152 | - same configurations as VSCode extension, `rust-analyzer.raLspServerPath`, `rust-analyzer.enableCargoWatchOnStartup` etc. | 142 | - same configurations as VSCode extension, `rust-analyzer.raLspServerPath`, `rust-analyzer.enableCargoWatchOnStartup` etc. |
153 | - same commands too, `rust-analyzer.analyzerStatus`, `rust-analyzer.startCargoWatch` etc. | 143 | - same commands too, `rust-analyzer.analyzerStatus`, `rust-analyzer.startCargoWatch` etc. |
154 | - highlighting and inlay_hints are not implemented yet | 144 | - highlighting and inlay_hints are not implemented yet |
155 | 145 | ||
156 | [coc.nvim]: https://github.com/neoclide/coc.nvim | 146 | [coc.nvim]: https://github.com/neoclide/coc.nvim |
157 | [coc-vim-conf]: https://github.com/neoclide/coc.nvim/#example-vim-configuration | ||
158 | [coc-rust-analyzer]: https://github.com/fannheyward/coc-rust-analyzer | 147 | [coc-rust-analyzer]: https://github.com/fannheyward/coc-rust-analyzer |
159 | 148 | ||
160 | ## Vim and NeoVim Alternative | 149 | ## Vim and NeoVim (LanguageClient-neovim) |
161 | 150 | ||
162 | * Install LanguageClient-neovim by following the instructions [here][lang-client-neovim] | 151 | * Install LanguageClient-neovim by following the instructions [here][lang-client-neovim] |
163 | - No extra run-time is required as this server is written in Rust | ||
164 | - The github project wiki has extra tips on configuration | 152 | - The github project wiki has extra tips on configuration |
165 | 153 | ||
166 | * Configure by adding this to your vim/neovim config file (replacing the existing rust specific line if it exists): | 154 | * Configure by adding this to your vim/neovim config file (replacing the existing rust specific line if it exists): |
167 | 155 | ||
168 | ``` | 156 | ```vim |
169 | let g:LanguageClient_serverCommands = { | 157 | let g:LanguageClient_serverCommands = { |
170 | \ 'rust': ['ra_lsp_server'], | 158 | \ 'rust': ['ra_lsp_server'], |
171 | \ } | 159 | \ } |
@@ -173,6 +161,13 @@ let g:LanguageClient_serverCommands = { | |||
173 | 161 | ||
174 | [lang-client-neovim]: https://github.com/autozimu/LanguageClient-neovim | 162 | [lang-client-neovim]: https://github.com/autozimu/LanguageClient-neovim |
175 | 163 | ||
164 | ## NeoVim (nvim-lsp) | ||
165 | |||
166 | NeoVim 0.5 (not yet released) has built in language server support. For a quick start configuration | ||
167 | of rust-analyzer, use [neovim/nvim-lsp](https://github.com/neovim/nvim-lsp#rust_analyzer). | ||
168 | Once `neovim/nvim-lsp` is installed, you can use `call nvim_lsp#setup("rust_analyzer", {})` | ||
169 | or `lua require'nvim_lsp'.rust_analyzer.setup({})` to quickly get set up. | ||
170 | |||
176 | 171 | ||
177 | ## Sublime Text 3 | 172 | ## Sublime Text 3 |
178 | 173 | ||
diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs index 190baeddf..40a6682be 100644 --- a/xtask/src/lib.rs +++ b/xtask/src/lib.rs | |||
@@ -144,6 +144,7 @@ pub fn run_fuzzer() -> Result<()> { | |||
144 | } | 144 | } |
145 | 145 | ||
146 | pub fn reformat_staged_files() -> Result<()> { | 146 | pub fn reformat_staged_files() -> Result<()> { |
147 | run_rustfmt(Mode::Overwrite)?; | ||
147 | let root = project_root(); | 148 | let root = project_root(); |
148 | let output = Command::new("git") | 149 | let output = Command::new("git") |
149 | .arg("diff") | 150 | .arg("diff") |