diff options
Diffstat (limited to 'crates/ra_assists/src/assists')
-rw-r--r-- | crates/ra_assists/src/assists/add_import.rs | 10 | ||||
-rw-r--r-- | crates/ra_assists/src/assists/auto_import.rs | 72 |
2 files changed, 54 insertions, 28 deletions
diff --git a/crates/ra_assists/src/assists/add_import.rs b/crates/ra_assists/src/assists/add_import.rs index bf6cfe865..fc038df78 100644 --- a/crates/ra_assists/src/assists/add_import.rs +++ b/crates/ra_assists/src/assists/add_import.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use hir::{self, db::HirDatabase}; | 1 | use hir::{self, db::HirDatabase, ModPath}; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | ast::{self, NameOwner}, | 3 | ast::{self, NameOwner}, |
4 | AstNode, Direction, SmolStr, | 4 | AstNode, Direction, SmolStr, |
@@ -20,10 +20,10 @@ pub fn auto_import_text_edit( | |||
20 | position: &SyntaxNode, | 20 | position: &SyntaxNode, |
21 | // The statement to use as anchor (last resort) | 21 | // The statement to use as anchor (last resort) |
22 | anchor: &SyntaxNode, | 22 | anchor: &SyntaxNode, |
23 | // The path to import as a sequence of strings | 23 | path_to_import: &ModPath, |
24 | target: &[SmolStr], | ||
25 | edit: &mut TextEditBuilder, | 24 | edit: &mut TextEditBuilder, |
26 | ) { | 25 | ) { |
26 | let target = path_to_import.to_string().split("::").map(SmolStr::new).collect::<Vec<_>>(); | ||
27 | let container = position.ancestors().find_map(|n| { | 27 | let container = position.ancestors().find_map(|n| { |
28 | if let Some(module) = ast::Module::cast(n.clone()) { | 28 | if let Some(module) = ast::Module::cast(n.clone()) { |
29 | return module.item_list().map(|it| it.syntax().clone()); | 29 | return module.item_list().map(|it| it.syntax().clone()); |
@@ -32,8 +32,8 @@ pub fn auto_import_text_edit( | |||
32 | }); | 32 | }); |
33 | 33 | ||
34 | if let Some(container) = container { | 34 | if let Some(container) = container { |
35 | let action = best_action_for_target(container, anchor.clone(), target); | 35 | let action = best_action_for_target(container, anchor.clone(), &target); |
36 | make_assist(&action, target, edit); | 36 | make_assist(&action, &target, edit); |
37 | } | 37 | } |
38 | } | 38 | } |
39 | 39 | ||
diff --git a/crates/ra_assists/src/assists/auto_import.rs b/crates/ra_assists/src/assists/auto_import.rs index 8c483e2da..2068256b0 100644 --- a/crates/ra_assists/src/assists/auto_import.rs +++ b/crates/ra_assists/src/assists/auto_import.rs | |||
@@ -1,8 +1,6 @@ | |||
1 | use hir::db::HirDatabase; | 1 | use hir::{db::HirDatabase, ModPath}; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | ast::{self, AstNode}, | 3 | ast::{self, AstNode}, |
4 | SmolStr, | ||
5 | SyntaxKind::USE_ITEM, | ||
6 | SyntaxNode, | 4 | SyntaxNode, |
7 | }; | 5 | }; |
8 | 6 | ||
@@ -34,9 +32,11 @@ pub(crate) fn auto_import<F: ImportsLocator>( | |||
34 | ) -> Option<Assist> { | 32 | ) -> Option<Assist> { |
35 | let path_to_import: ast::Path = ctx.find_node_at_offset()?; | 33 | let path_to_import: ast::Path = ctx.find_node_at_offset()?; |
36 | let path_to_import_syntax = path_to_import.syntax(); | 34 | let path_to_import_syntax = path_to_import.syntax(); |
37 | if path_to_import_syntax.ancestors().find(|ancestor| ancestor.kind() == USE_ITEM).is_some() { | 35 | if path_to_import_syntax.ancestors().find_map(ast::UseItem::cast).is_some() { |
38 | return None; | 36 | return None; |
39 | } | 37 | } |
38 | let name_to_import = | ||
39 | path_to_import_syntax.descendants().find_map(ast::NameRef::cast)?.syntax().to_string(); | ||
40 | 40 | ||
41 | let module = path_to_import_syntax.ancestors().find_map(ast::Module::cast); | 41 | let module = path_to_import_syntax.ancestors().find_map(ast::Module::cast); |
42 | let position = match module.and_then(|it| it.item_list()) { | 42 | let position = match module.and_then(|it| it.item_list()) { |
@@ -53,38 +53,28 @@ pub(crate) fn auto_import<F: ImportsLocator>( | |||
53 | } | 53 | } |
54 | 54 | ||
55 | let proposed_imports = imports_locator | 55 | let proposed_imports = imports_locator |
56 | .find_imports(&path_to_import_syntax.to_string()) | 56 | .find_imports(&name_to_import) |
57 | .into_iter() | 57 | .into_iter() |
58 | .filter_map(|module_def| module_with_name_to_import.find_use_path(ctx.db, module_def)) | 58 | .filter_map(|module_def| module_with_name_to_import.find_use_path(ctx.db, module_def)) |
59 | .filter(|use_path| !use_path.segments.is_empty()) | 59 | .filter(|use_path| !use_path.segments.is_empty()) |
60 | .take(20) | 60 | .take(20) |
61 | .map(|import| import.to_string()) | ||
62 | .collect::<std::collections::BTreeSet<_>>(); | 61 | .collect::<std::collections::BTreeSet<_>>(); |
63 | if proposed_imports.is_empty() { | 62 | if proposed_imports.is_empty() { |
64 | return None; | 63 | return None; |
65 | } | 64 | } |
66 | 65 | ||
67 | ctx.add_assist_group( | 66 | ctx.add_assist_group(AssistId("auto_import"), format!("Import {}", name_to_import), || { |
68 | AssistId("auto_import"), | 67 | proposed_imports |
69 | format!("Import {}", path_to_import_syntax), | 68 | .into_iter() |
70 | || { | 69 | .map(|import| import_to_action(import, &position, &path_to_import_syntax)) |
71 | proposed_imports | 70 | .collect() |
72 | .into_iter() | 71 | }) |
73 | .map(|import| import_to_action(import, &position, &path_to_import_syntax)) | ||
74 | .collect() | ||
75 | }, | ||
76 | ) | ||
77 | } | 72 | } |
78 | 73 | ||
79 | fn import_to_action(import: String, position: &SyntaxNode, anchor: &SyntaxNode) -> ActionBuilder { | 74 | fn import_to_action(import: ModPath, position: &SyntaxNode, anchor: &SyntaxNode) -> ActionBuilder { |
80 | let mut action_builder = ActionBuilder::default(); | 75 | let mut action_builder = ActionBuilder::default(); |
81 | action_builder.label(format!("Import `{}`", &import)); | 76 | action_builder.label(format!("Import `{}`", &import)); |
82 | auto_import_text_edit( | 77 | auto_import_text_edit(position, anchor, &import, action_builder.text_edit_builder()); |
83 | position, | ||
84 | anchor, | ||
85 | &[SmolStr::new(import)], | ||
86 | action_builder.text_edit_builder(), | ||
87 | ); | ||
88 | action_builder | 78 | action_builder |
89 | } | 79 | } |
90 | 80 | ||
@@ -121,6 +111,42 @@ mod tests { | |||
121 | } | 111 | } |
122 | 112 | ||
123 | #[test] | 113 | #[test] |
114 | fn auto_imports_are_merged() { | ||
115 | check_assist_with_imports_locator( | ||
116 | auto_import, | ||
117 | TestImportsLocator::new, | ||
118 | r" | ||
119 | use PubMod::PubStruct1; | ||
120 | |||
121 | struct Test { | ||
122 | test: Pub<|>Struct2<u8>, | ||
123 | } | ||
124 | |||
125 | pub mod PubMod { | ||
126 | pub struct PubStruct1; | ||
127 | pub struct PubStruct2<T> { | ||
128 | _t: T, | ||
129 | } | ||
130 | } | ||
131 | ", | ||
132 | r" | ||
133 | use PubMod::{PubStruct2, PubStruct1}; | ||
134 | |||
135 | struct Test { | ||
136 | test: Pub<|>Struct2<u8>, | ||
137 | } | ||
138 | |||
139 | pub mod PubMod { | ||
140 | pub struct PubStruct1; | ||
141 | pub struct PubStruct2<T> { | ||
142 | _t: T, | ||
143 | } | ||
144 | } | ||
145 | ", | ||
146 | ); | ||
147 | } | ||
148 | |||
149 | #[test] | ||
124 | fn applicable_when_found_multiple_imports() { | 150 | fn applicable_when_found_multiple_imports() { |
125 | check_assist_with_imports_locator( | 151 | check_assist_with_imports_locator( |
126 | auto_import, | 152 | auto_import, |