aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_ide/src/display/navigation_target.rs15
-rw-r--r--crates/ra_ide/src/goto_definition.rs169
-rw-r--r--crates/test_utils/src/lib.rs4
-rw-r--r--docs/user/README.md29
-rw-r--r--xtask/src/lib.rs1
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 {
328impl ToNav for hir::Local { 328impl 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
140Neovim 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)
141rust-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:
142Once `neovim/nvim-lsp` is installed, you can use `call nvim_lsp#setup("rust_analyzer", {})`
143or `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
169let g:LanguageClient_serverCommands = { 157let 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
166NeoVim 0.5 (not yet released) has built in language server support. For a quick start configuration
167of rust-analyzer, use [neovim/nvim-lsp](https://github.com/neovim/nvim-lsp#rust_analyzer).
168Once `neovim/nvim-lsp` is installed, you can use `call nvim_lsp#setup("rust_analyzer", {})`
169or `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
146pub fn reformat_staged_files() -> Result<()> { 146pub 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")