aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists')
-rw-r--r--crates/ra_assists/src/assists/add_import.rs (renamed from crates/ra_assists/src/assists/auto_import.rs)196
-rw-r--r--crates/ra_assists/src/lib.rs6
2 files changed, 101 insertions, 101 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
3use hir::{self, db::HirDatabase}; 3use hir::{self, db::HirDatabase};
4use ra_text_edit::TextEditBuilder;
5
6use crate::{
7 assist_ctx::{Assist, AssistCtx},
8 AssistId,
9};
10use ra_syntax::{ 4use 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};
10use ra_text_edit::TextEditBuilder;
11
12use 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
20pub 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
42pub(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
17fn collect_path_segments_raw( 89fn 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
508pub fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> { 580fn 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
527pub 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
549pub(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)]
597mod tests { 597mod 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 "
606std::fmt::Debug<|> 606std::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 "
620std::fmt::Debug<|> 620std::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 "
641fn main() { 641fn 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 "
662std::fmt<|>::Debug 662std::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 "
677use stdx; 677use 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 "
697impl std::fmt::Debug<|> for Foo { 697impl 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 "
731use std::fmt; 731use 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 "
750use std::fmt; 750use 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 "
769use std::fmt::Debug; 769use 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 "
788use std::fmt::{Debug, nested::{Display}}; 788use 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 "
807use std::fmt::{Debug, nested::{self, Display}}; 807use 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 "
826use std::fmt::{Debug, nested::{Display}}; 826use 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 "
845use std::fmt::Debug; 845use 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 "
864use std::fmt::nested::Debug; 864use 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 "
883use std::fmt as foo; 883use 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 "
902impl foo<|> for Foo { 902impl 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 "
913use std::fmt<|>; 913use 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 "
923mod foo { 923mod foo {
924 mod bar { 924 mod bar {
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index 871d49960..7a1657d87 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -17,7 +17,7 @@ use ra_syntax::{TextRange, TextUnit};
17use ra_text_edit::TextEdit; 17use ra_text_edit::TextEdit;
18 18
19pub(crate) use crate::assist_ctx::{Assist, AssistCtx}; 19pub(crate) use crate::assist_ctx::{Assist, AssistCtx};
20pub use crate::assists::auto_import::auto_import_text_edit; 20pub use crate::assists::add_import::auto_import_text_edit;
21 21
22/// Unique identifier of the assist, should not be shown to the user 22/// Unique identifier of the assist, should not be shown to the user
23/// directly. 23/// directly.
@@ -107,7 +107,7 @@ mod assists {
107 mod replace_if_let_with_match; 107 mod replace_if_let_with_match;
108 mod split_import; 108 mod split_import;
109 mod remove_dbg; 109 mod remove_dbg;
110 pub(crate) mod auto_import; 110 pub(crate) mod add_import;
111 mod add_missing_impl_members; 111 mod add_missing_impl_members;
112 mod move_guard; 112 mod move_guard;
113 mod move_bounds; 113 mod move_bounds;
@@ -129,7 +129,7 @@ mod assists {
129 replace_if_let_with_match::replace_if_let_with_match, 129 replace_if_let_with_match::replace_if_let_with_match,
130 split_import::split_import, 130 split_import::split_import,
131 remove_dbg::remove_dbg, 131 remove_dbg::remove_dbg,
132 auto_import::auto_import, 132 add_import::add_import,
133 add_missing_impl_members::add_missing_impl_members, 133 add_missing_impl_members::add_missing_impl_members,
134 add_missing_impl_members::add_missing_default_members, 134 add_missing_impl_members::add_missing_default_members,
135 inline_local_variable::inline_local_varialbe, 135 inline_local_variable::inline_local_varialbe,