diff options
-rw-r--r-- | crates/ide_assists/src/assist_context.rs | 8 | ||||
-rw-r--r-- | crates/ide_assists/src/handlers/expand_glob_import.rs | 90 | ||||
-rw-r--r-- | crates/syntax/src/ted.rs | 5 |
3 files changed, 38 insertions, 65 deletions
diff --git a/crates/ide_assists/src/assist_context.rs b/crates/ide_assists/src/assist_context.rs index 112939948..682f0ff5e 100644 --- a/crates/ide_assists/src/assist_context.rs +++ b/crates/ide_assists/src/assist_context.rs | |||
@@ -13,7 +13,7 @@ use ide_db::{ | |||
13 | RootDatabase, | 13 | RootDatabase, |
14 | }; | 14 | }; |
15 | use syntax::{ | 15 | use syntax::{ |
16 | algo::{self, find_node_at_offset, find_node_at_range, SyntaxRewriter}, | 16 | algo::{self, find_node_at_offset, find_node_at_range}, |
17 | AstNode, AstToken, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxNodePtr, | 17 | AstNode, AstToken, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxNodePtr, |
18 | SyntaxToken, TextRange, TextSize, TokenAtOffset, | 18 | SyntaxToken, TextRange, TextSize, TokenAtOffset, |
19 | }; | 19 | }; |
@@ -290,12 +290,6 @@ impl AssistBuilder { | |||
290 | pub(crate) fn replace_ast<N: AstNode>(&mut self, old: N, new: N) { | 290 | pub(crate) fn replace_ast<N: AstNode>(&mut self, old: N, new: N) { |
291 | algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit) | 291 | algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit) |
292 | } | 292 | } |
293 | pub(crate) fn rewrite(&mut self, rewriter: SyntaxRewriter) { | ||
294 | if let Some(node) = rewriter.rewrite_root() { | ||
295 | let new = rewriter.rewrite(&node); | ||
296 | algo::diff(&node, &new).into_text_edit(&mut self.edit); | ||
297 | } | ||
298 | } | ||
299 | pub(crate) fn create_file(&mut self, dst: AnchoredPathBuf, content: impl Into<String>) { | 293 | pub(crate) fn create_file(&mut self, dst: AnchoredPathBuf, content: impl Into<String>) { |
300 | let file_system_edit = | 294 | let file_system_edit = |
301 | FileSystemEdit::CreateFile { dst: dst, initial_contents: content.into() }; | 295 | FileSystemEdit::CreateFile { dst: dst, initial_contents: content.into() }; |
diff --git a/crates/ide_assists/src/handlers/expand_glob_import.rs b/crates/ide_assists/src/handlers/expand_glob_import.rs index 98389e4f7..e3095f26b 100644 --- a/crates/ide_assists/src/handlers/expand_glob_import.rs +++ b/crates/ide_assists/src/handlers/expand_glob_import.rs | |||
@@ -4,10 +4,10 @@ use ide_db::{ | |||
4 | defs::{Definition, NameRefClass}, | 4 | defs::{Definition, NameRefClass}, |
5 | search::SearchScope, | 5 | search::SearchScope, |
6 | }; | 6 | }; |
7 | use stdx::never; | ||
7 | use syntax::{ | 8 | use syntax::{ |
8 | algo::SyntaxRewriter, | ||
9 | ast::{self, make}, | 9 | ast::{self, make}, |
10 | AstNode, Direction, SyntaxNode, SyntaxToken, T, | 10 | ted, AstNode, Direction, SyntaxNode, SyntaxToken, T, |
11 | }; | 11 | }; |
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
@@ -42,6 +42,7 @@ use crate::{ | |||
42 | // ``` | 42 | // ``` |
43 | pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 43 | pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
44 | let star = ctx.find_token_syntax_at_offset(T![*])?; | 44 | let star = ctx.find_token_syntax_at_offset(T![*])?; |
45 | let use_tree = star.parent().and_then(ast::UseTree::cast)?; | ||
45 | let (parent, mod_path) = find_parent_and_path(&star)?; | 46 | let (parent, mod_path) = find_parent_and_path(&star)?; |
46 | let target_module = match ctx.sema.resolve_path(&mod_path)? { | 47 | let target_module = match ctx.sema.resolve_path(&mod_path)? { |
47 | PathResolution::Def(ModuleDef::Module(it)) => it, | 48 | PathResolution::Def(ModuleDef::Module(it)) => it, |
@@ -53,7 +54,6 @@ pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Opti | |||
53 | 54 | ||
54 | let refs_in_target = find_refs_in_mod(ctx, target_module, Some(current_module))?; | 55 | let refs_in_target = find_refs_in_mod(ctx, target_module, Some(current_module))?; |
55 | let imported_defs = find_imported_defs(ctx, star)?; | 56 | let imported_defs = find_imported_defs(ctx, star)?; |
56 | let names_to_import = find_names_to_import(ctx, refs_in_target, imported_defs); | ||
57 | 57 | ||
58 | let target = parent.clone().either(|n| n.syntax().clone(), |n| n.syntax().clone()); | 58 | let target = parent.clone().either(|n| n.syntax().clone(), |n| n.syntax().clone()); |
59 | acc.add( | 59 | acc.add( |
@@ -61,9 +61,32 @@ pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Opti | |||
61 | "Expand glob import", | 61 | "Expand glob import", |
62 | target.text_range(), | 62 | target.text_range(), |
63 | |builder| { | 63 | |builder| { |
64 | let mut rewriter = SyntaxRewriter::default(); | 64 | let use_tree = builder.make_ast_mut(use_tree); |
65 | replace_ast(&mut rewriter, parent, mod_path, names_to_import); | 65 | |
66 | builder.rewrite(rewriter); | 66 | let names_to_import = find_names_to_import(ctx, refs_in_target, imported_defs); |
67 | let expanded = make::use_tree_list(names_to_import.iter().map(|n| { | ||
68 | let path = | ||
69 | make::path_unqualified(make::path_segment(make::name_ref(&n.to_string()))); | ||
70 | make::use_tree(path, None, None, false) | ||
71 | })) | ||
72 | .clone_for_update(); | ||
73 | |||
74 | match use_tree.star_token() { | ||
75 | Some(star) => { | ||
76 | let needs_braces = use_tree.path().is_some() && names_to_import.len() > 1; | ||
77 | if needs_braces { | ||
78 | ted::replace(star, expanded.syntax()) | ||
79 | } else { | ||
80 | let without_braces = expanded | ||
81 | .syntax() | ||
82 | .children_with_tokens() | ||
83 | .filter(|child| !matches!(child.kind(), T!['{'] | T!['}'])) | ||
84 | .collect(); | ||
85 | ted::replace_with_many(star, without_braces) | ||
86 | } | ||
87 | } | ||
88 | None => never!(), | ||
89 | } | ||
67 | }, | 90 | }, |
68 | ) | 91 | ) |
69 | } | 92 | } |
@@ -232,53 +255,6 @@ fn find_names_to_import( | |||
232 | used_refs.0.iter().map(|r| r.visible_name.clone()).collect() | 255 | used_refs.0.iter().map(|r| r.visible_name.clone()).collect() |
233 | } | 256 | } |
234 | 257 | ||
235 | fn replace_ast( | ||
236 | rewriter: &mut SyntaxRewriter, | ||
237 | parent: Either<ast::UseTree, ast::UseTreeList>, | ||
238 | path: ast::Path, | ||
239 | names_to_import: Vec<Name>, | ||
240 | ) { | ||
241 | let existing_use_trees = match parent.clone() { | ||
242 | Either::Left(_) => vec![], | ||
243 | Either::Right(u) => u | ||
244 | .use_trees() | ||
245 | .filter(|n| | ||
246 | // filter out star | ||
247 | n.star_token().is_none()) | ||
248 | .collect(), | ||
249 | }; | ||
250 | |||
251 | let new_use_trees: Vec<ast::UseTree> = names_to_import | ||
252 | .iter() | ||
253 | .map(|n| { | ||
254 | let path = make::path_unqualified(make::path_segment(make::name_ref(&n.to_string()))); | ||
255 | make::use_tree(path, None, None, false) | ||
256 | }) | ||
257 | .collect(); | ||
258 | |||
259 | let use_trees = [&existing_use_trees[..], &new_use_trees[..]].concat(); | ||
260 | |||
261 | match use_trees.as_slice() { | ||
262 | [name] => { | ||
263 | if let Some(end_path) = name.path() { | ||
264 | rewriter.replace_ast( | ||
265 | &parent.left_or_else(|tl| tl.parent_use_tree()), | ||
266 | &make::use_tree(make::path_concat(path, end_path), None, None, false), | ||
267 | ); | ||
268 | } | ||
269 | } | ||
270 | names => match &parent { | ||
271 | Either::Left(parent) => rewriter.replace_ast( | ||
272 | parent, | ||
273 | &make::use_tree(path, Some(make::use_tree_list(names.to_owned())), None, false), | ||
274 | ), | ||
275 | Either::Right(parent) => { | ||
276 | rewriter.replace_ast(parent, &make::use_tree_list(names.to_owned())) | ||
277 | } | ||
278 | }, | ||
279 | }; | ||
280 | } | ||
281 | |||
282 | #[cfg(test)] | 258 | #[cfg(test)] |
283 | mod tests { | 259 | mod tests { |
284 | use crate::tests::{check_assist, check_assist_not_applicable}; | 260 | use crate::tests::{check_assist, check_assist_not_applicable}; |
@@ -350,7 +326,7 @@ mod foo { | |||
350 | pub fn f() {} | 326 | pub fn f() {} |
351 | } | 327 | } |
352 | 328 | ||
353 | use foo::{f, Baz, Bar}; | 329 | use foo::{Baz, Bar, f}; |
354 | 330 | ||
355 | fn qux(bar: Bar, baz: Baz) { | 331 | fn qux(bar: Bar, baz: Baz) { |
356 | f(); | 332 | f(); |
@@ -389,7 +365,7 @@ mod foo { | |||
389 | } | 365 | } |
390 | 366 | ||
391 | use foo::Bar; | 367 | use foo::Bar; |
392 | use foo::{f, Baz}; | 368 | use foo::{Baz, f}; |
393 | 369 | ||
394 | fn qux(bar: Bar, baz: Baz) { | 370 | fn qux(bar: Bar, baz: Baz) { |
395 | f(); | 371 | f(); |
@@ -439,7 +415,7 @@ mod foo { | |||
439 | } | 415 | } |
440 | } | 416 | } |
441 | 417 | ||
442 | use foo::{bar::{f, Baz, Bar}, baz::*}; | 418 | use foo::{bar::{Baz, Bar, f}, baz::*}; |
443 | 419 | ||
444 | fn qux(bar: Bar, baz: Baz) { | 420 | fn qux(bar: Bar, baz: Baz) { |
445 | f(); | 421 | f(); |
@@ -891,7 +867,7 @@ mod foo { | |||
891 | pub struct Bar; | 867 | pub struct Bar; |
892 | } | 868 | } |
893 | 869 | ||
894 | use foo::Bar; | 870 | use foo::{Bar}; |
895 | 871 | ||
896 | struct Baz { | 872 | struct Baz { |
897 | bar: Bar | 873 | bar: Bar |
diff --git a/crates/syntax/src/ted.rs b/crates/syntax/src/ted.rs index 91a06101f..a50c0dbca 100644 --- a/crates/syntax/src/ted.rs +++ b/crates/syntax/src/ted.rs | |||
@@ -125,8 +125,11 @@ pub fn remove_all_iter(range: impl IntoIterator<Item = SyntaxElement>) { | |||
125 | } | 125 | } |
126 | 126 | ||
127 | pub fn replace(old: impl Element, new: impl Element) { | 127 | pub fn replace(old: impl Element, new: impl Element) { |
128 | replace_with_many(old, vec![new.syntax_element()]) | ||
129 | } | ||
130 | pub fn replace_with_many(old: impl Element, new: Vec<SyntaxElement>) { | ||
128 | let old = old.syntax_element(); | 131 | let old = old.syntax_element(); |
129 | replace_all(old.clone()..=old, vec![new.syntax_element()]) | 132 | replace_all(old.clone()..=old, new) |
130 | } | 133 | } |
131 | pub fn replace_all(range: RangeInclusive<SyntaxElement>, new: Vec<SyntaxElement>) { | 134 | pub fn replace_all(range: RangeInclusive<SyntaxElement>, new: Vec<SyntaxElement>) { |
132 | let start = range.start().index(); | 135 | let start = range.start().index(); |