diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-10-27 14:13:09 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2019-10-27 14:13:09 +0000 |
commit | ad950830d0902aaacfb5a76355a203626eb93b5f (patch) | |
tree | 2b782268a2d4e7fcc9a3a33f0ea805aee9d373fa /crates/ra_assists/src/assists | |
parent | 6a454c7133f8f4a8c167f9b0422c719062574e5b (diff) | |
parent | be0f48f7cf801a6330d3e6a65b3352d544d32f63 (diff) |
Merge #2090
2090: move public stuff to top r=matklad a=matklad
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_assists/src/assists')
-rw-r--r-- | crates/ra_assists/src/assists/add_import.rs (renamed from crates/ra_assists/src/assists/auto_import.rs) | 196 |
1 files changed, 98 insertions, 98 deletions
diff --git a/crates/ra_assists/src/assists/auto_import.rs b/crates/ra_assists/src/assists/add_import.rs index a1c2aaa72..149d1403f 100644 --- a/crates/ra_assists/src/assists/auto_import.rs +++ b/crates/ra_assists/src/assists/add_import.rs | |||
@@ -1,18 +1,90 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir::{self, db::HirDatabase}; | 3 | use hir::{self, db::HirDatabase}; |
4 | use ra_text_edit::TextEditBuilder; | ||
5 | |||
6 | use crate::{ | ||
7 | assist_ctx::{Assist, AssistCtx}, | ||
8 | AssistId, | ||
9 | }; | ||
10 | use ra_syntax::{ | 4 | use ra_syntax::{ |
11 | ast::{self, NameOwner}, | 5 | ast::{self, NameOwner}, |
12 | AstNode, Direction, SmolStr, | 6 | AstNode, Direction, SmolStr, |
13 | SyntaxKind::{PATH, PATH_SEGMENT}, | 7 | SyntaxKind::{PATH, PATH_SEGMENT}, |
14 | SyntaxNode, TextRange, T, | 8 | SyntaxNode, TextRange, T, |
15 | }; | 9 | }; |
10 | use ra_text_edit::TextEditBuilder; | ||
11 | |||
12 | use crate::{ | ||
13 | assist_ctx::{Assist, AssistCtx}, | ||
14 | AssistId, | ||
15 | }; | ||
16 | |||
17 | // This function produces sequence of text edits into edit | ||
18 | // to import the target path in the most appropriate scope given | ||
19 | // the cursor position | ||
20 | pub fn auto_import_text_edit( | ||
21 | // Ideally the position of the cursor, used to | ||
22 | position: &SyntaxNode, | ||
23 | // The statement to use as anchor (last resort) | ||
24 | anchor: &SyntaxNode, | ||
25 | // The path to import as a sequence of strings | ||
26 | target: &[SmolStr], | ||
27 | edit: &mut TextEditBuilder, | ||
28 | ) { | ||
29 | let container = position.ancestors().find_map(|n| { | ||
30 | if let Some(module) = ast::Module::cast(n.clone()) { | ||
31 | return module.item_list().map(|it| it.syntax().clone()); | ||
32 | } | ||
33 | ast::SourceFile::cast(n).map(|it| it.syntax().clone()) | ||
34 | }); | ||
35 | |||
36 | if let Some(container) = container { | ||
37 | let action = best_action_for_target(container, anchor.clone(), target); | ||
38 | make_assist(&action, target, edit); | ||
39 | } | ||
40 | } | ||
41 | |||
42 | pub(crate) fn add_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | ||
43 | let path: ast::Path = ctx.find_node_at_offset()?; | ||
44 | // We don't want to mess with use statements | ||
45 | if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() { | ||
46 | return None; | ||
47 | } | ||
48 | |||
49 | let hir_path = hir::Path::from_ast(path.clone())?; | ||
50 | let segments = collect_hir_path_segments(&hir_path)?; | ||
51 | if segments.len() < 2 { | ||
52 | return None; | ||
53 | } | ||
54 | |||
55 | if let Some(module) = path.syntax().ancestors().find_map(ast::Module::cast) { | ||
56 | if let (Some(item_list), Some(name)) = (module.item_list(), module.name()) { | ||
57 | ctx.add_action( | ||
58 | AssistId("add_import"), | ||
59 | format!("import {} in mod {}", fmt_segments(&segments), name.text()), | ||
60 | |edit| { | ||
61 | apply_auto_import( | ||
62 | item_list.syntax(), | ||
63 | &path, | ||
64 | &segments, | ||
65 | edit.text_edit_builder(), | ||
66 | ); | ||
67 | }, | ||
68 | ); | ||
69 | } | ||
70 | } else { | ||
71 | let current_file = path.syntax().ancestors().find_map(ast::SourceFile::cast)?; | ||
72 | ctx.add_action( | ||
73 | AssistId("add_import"), | ||
74 | format!("import {} in the current file", fmt_segments(&segments)), | ||
75 | |edit| { | ||
76 | apply_auto_import( | ||
77 | current_file.syntax(), | ||
78 | &path, | ||
79 | &segments, | ||
80 | edit.text_edit_builder(), | ||
81 | ); | ||
82 | }, | ||
83 | ); | ||
84 | } | ||
85 | |||
86 | ctx.build() | ||
87 | } | ||
16 | 88 | ||
17 | fn collect_path_segments_raw( | 89 | fn collect_path_segments_raw( |
18 | segments: &mut Vec<ast::PathSegment>, | 90 | segments: &mut Vec<ast::PathSegment>, |
@@ -505,7 +577,7 @@ fn apply_auto_import( | |||
505 | } | 577 | } |
506 | } | 578 | } |
507 | 579 | ||
508 | pub fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> { | 580 | fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> { |
509 | let mut ps = Vec::<SmolStr>::with_capacity(10); | 581 | let mut ps = Vec::<SmolStr>::with_capacity(10); |
510 | match path.kind { | 582 | match path.kind { |
511 | hir::PathKind::Abs => ps.push("".into()), | 583 | hir::PathKind::Abs => ps.push("".into()), |
@@ -521,78 +593,6 @@ pub fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> { | |||
521 | Some(ps) | 593 | Some(ps) |
522 | } | 594 | } |
523 | 595 | ||
524 | // This function produces sequence of text edits into edit | ||
525 | // to import the target path in the most appropriate scope given | ||
526 | // the cursor position | ||
527 | pub fn auto_import_text_edit( | ||
528 | // Ideally the position of the cursor, used to | ||
529 | position: &SyntaxNode, | ||
530 | // The statement to use as anchor (last resort) | ||
531 | anchor: &SyntaxNode, | ||
532 | // The path to import as a sequence of strings | ||
533 | target: &[SmolStr], | ||
534 | edit: &mut TextEditBuilder, | ||
535 | ) { | ||
536 | let container = position.ancestors().find_map(|n| { | ||
537 | if let Some(module) = ast::Module::cast(n.clone()) { | ||
538 | return module.item_list().map(|it| it.syntax().clone()); | ||
539 | } | ||
540 | ast::SourceFile::cast(n).map(|it| it.syntax().clone()) | ||
541 | }); | ||
542 | |||
543 | if let Some(container) = container { | ||
544 | let action = best_action_for_target(container, anchor.clone(), target); | ||
545 | make_assist(&action, target, edit); | ||
546 | } | ||
547 | } | ||
548 | |||
549 | pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | ||
550 | let path: ast::Path = ctx.find_node_at_offset()?; | ||
551 | // We don't want to mess with use statements | ||
552 | if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() { | ||
553 | return None; | ||
554 | } | ||
555 | |||
556 | let hir_path = hir::Path::from_ast(path.clone())?; | ||
557 | let segments = collect_hir_path_segments(&hir_path)?; | ||
558 | if segments.len() < 2 { | ||
559 | return None; | ||
560 | } | ||
561 | |||
562 | if let Some(module) = path.syntax().ancestors().find_map(ast::Module::cast) { | ||
563 | if let (Some(item_list), Some(name)) = (module.item_list(), module.name()) { | ||
564 | ctx.add_action( | ||
565 | AssistId("auto_import"), | ||
566 | format!("import {} in mod {}", fmt_segments(&segments), name.text()), | ||
567 | |edit| { | ||
568 | apply_auto_import( | ||
569 | item_list.syntax(), | ||
570 | &path, | ||
571 | &segments, | ||
572 | edit.text_edit_builder(), | ||
573 | ); | ||
574 | }, | ||
575 | ); | ||
576 | } | ||
577 | } else { | ||
578 | let current_file = path.syntax().ancestors().find_map(ast::SourceFile::cast)?; | ||
579 | ctx.add_action( | ||
580 | AssistId("auto_import"), | ||
581 | format!("import {} in the current file", fmt_segments(&segments)), | ||
582 | |edit| { | ||
583 | apply_auto_import( | ||
584 | current_file.syntax(), | ||
585 | &path, | ||
586 | &segments, | ||
587 | edit.text_edit_builder(), | ||
588 | ); | ||
589 | }, | ||
590 | ); | ||
591 | } | ||
592 | |||
593 | ctx.build() | ||
594 | } | ||
595 | |||
596 | #[cfg(test)] | 596 | #[cfg(test)] |
597 | mod tests { | 597 | mod tests { |
598 | use super::*; | 598 | use super::*; |
@@ -601,7 +601,7 @@ mod tests { | |||
601 | #[test] | 601 | #[test] |
602 | fn test_auto_import_add_use_no_anchor() { | 602 | fn test_auto_import_add_use_no_anchor() { |
603 | check_assist( | 603 | check_assist( |
604 | auto_import, | 604 | add_import, |
605 | " | 605 | " |
606 | std::fmt::Debug<|> | 606 | std::fmt::Debug<|> |
607 | ", | 607 | ", |
@@ -615,7 +615,7 @@ Debug<|> | |||
615 | #[test] | 615 | #[test] |
616 | fn test_auto_import_add_use_no_anchor_with_item_below() { | 616 | fn test_auto_import_add_use_no_anchor_with_item_below() { |
617 | check_assist( | 617 | check_assist( |
618 | auto_import, | 618 | add_import, |
619 | " | 619 | " |
620 | std::fmt::Debug<|> | 620 | std::fmt::Debug<|> |
621 | 621 | ||
@@ -636,7 +636,7 @@ fn main() { | |||
636 | #[test] | 636 | #[test] |
637 | fn test_auto_import_add_use_no_anchor_with_item_above() { | 637 | fn test_auto_import_add_use_no_anchor_with_item_above() { |
638 | check_assist( | 638 | check_assist( |
639 | auto_import, | 639 | add_import, |
640 | " | 640 | " |
641 | fn main() { | 641 | fn main() { |
642 | } | 642 | } |
@@ -657,7 +657,7 @@ Debug<|> | |||
657 | #[test] | 657 | #[test] |
658 | fn test_auto_import_add_use_no_anchor_2seg() { | 658 | fn test_auto_import_add_use_no_anchor_2seg() { |
659 | check_assist( | 659 | check_assist( |
660 | auto_import, | 660 | add_import, |
661 | " | 661 | " |
662 | std::fmt<|>::Debug | 662 | std::fmt<|>::Debug |
663 | ", | 663 | ", |
@@ -672,7 +672,7 @@ fmt<|>::Debug | |||
672 | #[test] | 672 | #[test] |
673 | fn test_auto_import_add_use() { | 673 | fn test_auto_import_add_use() { |
674 | check_assist( | 674 | check_assist( |
675 | auto_import, | 675 | add_import, |
676 | " | 676 | " |
677 | use stdx; | 677 | use stdx; |
678 | 678 | ||
@@ -692,7 +692,7 @@ impl Debug<|> for Foo { | |||
692 | #[test] | 692 | #[test] |
693 | fn test_auto_import_file_use_other_anchor() { | 693 | fn test_auto_import_file_use_other_anchor() { |
694 | check_assist( | 694 | check_assist( |
695 | auto_import, | 695 | add_import, |
696 | " | 696 | " |
697 | impl std::fmt::Debug<|> for Foo { | 697 | impl std::fmt::Debug<|> for Foo { |
698 | } | 698 | } |
@@ -709,7 +709,7 @@ impl Debug<|> for Foo { | |||
709 | #[test] | 709 | #[test] |
710 | fn test_auto_import_add_use_other_anchor_indent() { | 710 | fn test_auto_import_add_use_other_anchor_indent() { |
711 | check_assist( | 711 | check_assist( |
712 | auto_import, | 712 | add_import, |
713 | " | 713 | " |
714 | impl std::fmt::Debug<|> for Foo { | 714 | impl std::fmt::Debug<|> for Foo { |
715 | } | 715 | } |
@@ -726,7 +726,7 @@ impl Debug<|> for Foo { | |||
726 | #[test] | 726 | #[test] |
727 | fn test_auto_import_split_different() { | 727 | fn test_auto_import_split_different() { |
728 | check_assist( | 728 | check_assist( |
729 | auto_import, | 729 | add_import, |
730 | " | 730 | " |
731 | use std::fmt; | 731 | use std::fmt; |
732 | 732 | ||
@@ -745,7 +745,7 @@ impl io<|> for Foo { | |||
745 | #[test] | 745 | #[test] |
746 | fn test_auto_import_split_self_for_use() { | 746 | fn test_auto_import_split_self_for_use() { |
747 | check_assist( | 747 | check_assist( |
748 | auto_import, | 748 | add_import, |
749 | " | 749 | " |
750 | use std::fmt; | 750 | use std::fmt; |
751 | 751 | ||
@@ -764,7 +764,7 @@ impl Debug<|> for Foo { | |||
764 | #[test] | 764 | #[test] |
765 | fn test_auto_import_split_self_for_target() { | 765 | fn test_auto_import_split_self_for_target() { |
766 | check_assist( | 766 | check_assist( |
767 | auto_import, | 767 | add_import, |
768 | " | 768 | " |
769 | use std::fmt::Debug; | 769 | use std::fmt::Debug; |
770 | 770 | ||
@@ -783,7 +783,7 @@ impl fmt<|> for Foo { | |||
783 | #[test] | 783 | #[test] |
784 | fn test_auto_import_add_to_nested_self_nested() { | 784 | fn test_auto_import_add_to_nested_self_nested() { |
785 | check_assist( | 785 | check_assist( |
786 | auto_import, | 786 | add_import, |
787 | " | 787 | " |
788 | use std::fmt::{Debug, nested::{Display}}; | 788 | use std::fmt::{Debug, nested::{Display}}; |
789 | 789 | ||
@@ -802,7 +802,7 @@ impl nested<|> for Foo { | |||
802 | #[test] | 802 | #[test] |
803 | fn test_auto_import_add_to_nested_self_already_included() { | 803 | fn test_auto_import_add_to_nested_self_already_included() { |
804 | check_assist( | 804 | check_assist( |
805 | auto_import, | 805 | add_import, |
806 | " | 806 | " |
807 | use std::fmt::{Debug, nested::{self, Display}}; | 807 | use std::fmt::{Debug, nested::{self, Display}}; |
808 | 808 | ||
@@ -821,7 +821,7 @@ impl nested<|> for Foo { | |||
821 | #[test] | 821 | #[test] |
822 | fn test_auto_import_add_to_nested_nested() { | 822 | fn test_auto_import_add_to_nested_nested() { |
823 | check_assist( | 823 | check_assist( |
824 | auto_import, | 824 | add_import, |
825 | " | 825 | " |
826 | use std::fmt::{Debug, nested::{Display}}; | 826 | use std::fmt::{Debug, nested::{Display}}; |
827 | 827 | ||
@@ -840,7 +840,7 @@ impl Debug<|> for Foo { | |||
840 | #[test] | 840 | #[test] |
841 | fn test_auto_import_split_common_target_longer() { | 841 | fn test_auto_import_split_common_target_longer() { |
842 | check_assist( | 842 | check_assist( |
843 | auto_import, | 843 | add_import, |
844 | " | 844 | " |
845 | use std::fmt::Debug; | 845 | use std::fmt::Debug; |
846 | 846 | ||
@@ -859,7 +859,7 @@ impl Display<|> for Foo { | |||
859 | #[test] | 859 | #[test] |
860 | fn test_auto_import_split_common_use_longer() { | 860 | fn test_auto_import_split_common_use_longer() { |
861 | check_assist( | 861 | check_assist( |
862 | auto_import, | 862 | add_import, |
863 | " | 863 | " |
864 | use std::fmt::nested::Debug; | 864 | use std::fmt::nested::Debug; |
865 | 865 | ||
@@ -878,7 +878,7 @@ impl Display<|> for Foo { | |||
878 | #[test] | 878 | #[test] |
879 | fn test_auto_import_alias() { | 879 | fn test_auto_import_alias() { |
880 | check_assist( | 880 | check_assist( |
881 | auto_import, | 881 | add_import, |
882 | " | 882 | " |
883 | use std::fmt as foo; | 883 | use std::fmt as foo; |
884 | 884 | ||
@@ -897,7 +897,7 @@ impl Debug<|> for Foo { | |||
897 | #[test] | 897 | #[test] |
898 | fn test_auto_import_not_applicable_one_segment() { | 898 | fn test_auto_import_not_applicable_one_segment() { |
899 | check_assist_not_applicable( | 899 | check_assist_not_applicable( |
900 | auto_import, | 900 | add_import, |
901 | " | 901 | " |
902 | impl foo<|> for Foo { | 902 | impl foo<|> for Foo { |
903 | } | 903 | } |
@@ -908,7 +908,7 @@ impl foo<|> for Foo { | |||
908 | #[test] | 908 | #[test] |
909 | fn test_auto_import_not_applicable_in_use() { | 909 | fn test_auto_import_not_applicable_in_use() { |
910 | check_assist_not_applicable( | 910 | check_assist_not_applicable( |
911 | auto_import, | 911 | add_import, |
912 | " | 912 | " |
913 | use std::fmt<|>; | 913 | use std::fmt<|>; |
914 | ", | 914 | ", |
@@ -918,7 +918,7 @@ use std::fmt<|>; | |||
918 | #[test] | 918 | #[test] |
919 | fn test_auto_import_add_use_no_anchor_in_mod_mod() { | 919 | fn test_auto_import_add_use_no_anchor_in_mod_mod() { |
920 | check_assist( | 920 | check_assist( |
921 | auto_import, | 921 | add_import, |
922 | " | 922 | " |
923 | mod foo { | 923 | mod foo { |
924 | mod bar { | 924 | mod bar { |