diff options
Diffstat (limited to 'crates/ra_assists/src/handlers')
-rw-r--r-- | crates/ra_assists/src/handlers/merge_imports.rs | 72 |
1 files changed, 52 insertions, 20 deletions
diff --git a/crates/ra_assists/src/handlers/merge_imports.rs b/crates/ra_assists/src/handlers/merge_imports.rs index e9c49b7d0..89bc975bd 100644 --- a/crates/ra_assists/src/handlers/merge_imports.rs +++ b/crates/ra_assists/src/handlers/merge_imports.rs | |||
@@ -3,7 +3,7 @@ use std::iter::successors; | |||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | algo::neighbor, | 4 | algo::neighbor, |
5 | ast::{self, edit::AstNodeEdit, make}, | 5 | ast::{self, edit::AstNodeEdit, make}, |
6 | AstNode, AstToken, Direction, InsertPosition, SyntaxElement, T, | 6 | AstNode, AstToken, Direction, InsertPosition, SyntaxElement, TextRange, T, |
7 | }; | 7 | }; |
8 | 8 | ||
9 | use crate::{Assist, AssistCtx, AssistId}; | 9 | use crate::{Assist, AssistCtx, AssistId}; |
@@ -22,18 +22,15 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
22 | // ``` | 22 | // ``` |
23 | pub(crate) fn merge_imports(ctx: AssistCtx) -> Option<Assist> { | 23 | pub(crate) fn merge_imports(ctx: AssistCtx) -> Option<Assist> { |
24 | let tree: ast::UseTree = ctx.find_node_at_offset()?; | 24 | let tree: ast::UseTree = ctx.find_node_at_offset()?; |
25 | let use_item = tree.syntax().parent().and_then(ast::UseItem::cast)?; | 25 | let (new_tree, to_delete) = if let Some(use_item) = |
26 | let (merged, to_delete) = [Direction::Prev, Direction::Next] | 26 | tree.syntax().parent().and_then(ast::UseItem::cast) |
27 | .iter() | 27 | { |
28 | .copied() | 28 | let (merged, to_delete) = next_prev() |
29 | .filter_map(|dir| neighbor(&use_item, dir)) | 29 | .filter_map(|dir| neighbor(&use_item, dir)) |
30 | .filter_map(|it| Some((it.clone(), it.use_tree()?))) | 30 | .filter_map(|it| Some((it.clone(), it.use_tree()?))) |
31 | .find_map(|(use_item, use_tree)| { | 31 | .find_map(|(use_item, use_tree)| { |
32 | Some((try_merge_trees(&tree, &use_tree)?, use_item.clone())) | 32 | Some((try_merge_trees(&tree, &use_tree)?, use_item.clone())) |
33 | })?; | 33 | })?; |
34 | let mut offset = ctx.frange.range.start(); | ||
35 | ctx.add_assist(AssistId("merge_imports"), "Merge imports", |edit| { | ||
36 | edit.replace_ast(tree, merged); | ||
37 | 34 | ||
38 | let mut range = to_delete.syntax().text_range(); | 35 | let mut range = to_delete.syntax().text_range(); |
39 | let next_ws = to_delete | 36 | let next_ws = to_delete |
@@ -44,14 +41,41 @@ pub(crate) fn merge_imports(ctx: AssistCtx) -> Option<Assist> { | |||
44 | if let Some(ws) = next_ws { | 41 | if let Some(ws) = next_ws { |
45 | range = range.extend_to(&ws.syntax().text_range()) | 42 | range = range.extend_to(&ws.syntax().text_range()) |
46 | } | 43 | } |
47 | edit.delete(range); | 44 | (merged, range) |
48 | if range.end() <= offset { | 45 | } else { |
49 | offset -= range.len(); | 46 | let (merged, to_delete) = next_prev() |
47 | .filter_map(|dir| neighbor(&tree, dir)) | ||
48 | .find_map(|use_tree| Some((try_merge_trees(&tree, &use_tree)?, use_tree.clone())))?; | ||
49 | |||
50 | let mut range = to_delete.syntax().text_range(); | ||
51 | if let Some((dir, nb)) = next_prev().find_map(|dir| Some((dir, neighbor(&to_delete, dir)?))) | ||
52 | { | ||
53 | let nb_range = nb.syntax().text_range(); | ||
54 | if dir == Direction::Prev { | ||
55 | range = TextRange::from_to(nb_range.end(), range.end()); | ||
56 | } else { | ||
57 | range = TextRange::from_to(range.start(), nb_range.start()); | ||
58 | } | ||
59 | } | ||
60 | (merged, range) | ||
61 | }; | ||
62 | |||
63 | let mut offset = ctx.frange.range.start(); | ||
64 | ctx.add_assist(AssistId("merge_imports"), "Merge imports", |edit| { | ||
65 | edit.replace_ast(tree, new_tree); | ||
66 | edit.delete(to_delete); | ||
67 | |||
68 | if to_delete.end() <= offset { | ||
69 | offset -= to_delete.len(); | ||
50 | } | 70 | } |
51 | edit.set_cursor(offset); | 71 | edit.set_cursor(offset); |
52 | }) | 72 | }) |
53 | } | 73 | } |
54 | 74 | ||
75 | fn next_prev() -> impl Iterator<Item = Direction> { | ||
76 | [Direction::Next, Direction::Prev].iter().copied() | ||
77 | } | ||
78 | |||
55 | fn try_merge_trees(old: &ast::UseTree, new: &ast::UseTree) -> Option<ast::UseTree> { | 79 | fn try_merge_trees(old: &ast::UseTree, new: &ast::UseTree) -> Option<ast::UseTree> { |
56 | let lhs_path = old.path()?; | 80 | let lhs_path = old.path()?; |
57 | let rhs_path = new.path()?; | 81 | let rhs_path = new.path()?; |
@@ -134,11 +158,10 @@ use std::fmt<|>::Display; | |||
134 | r" | 158 | r" |
135 | use std::fmt<|>::{Display, Debug}; | 159 | use std::fmt<|>::{Display, Debug}; |
136 | ", | 160 | ", |
137 | ) | 161 | ); |
138 | } | 162 | } |
139 | 163 | ||
140 | #[test] | 164 | #[test] |
141 | #[ignore] | ||
142 | fn test_merge_nested() { | 165 | fn test_merge_nested() { |
143 | check_assist( | 166 | check_assist( |
144 | merge_imports, | 167 | merge_imports, |
@@ -146,8 +169,17 @@ use std::fmt<|>::{Display, Debug}; | |||
146 | use std::{fmt<|>::Debug, fmt::Display}; | 169 | use std::{fmt<|>::Debug, fmt::Display}; |
147 | ", | 170 | ", |
148 | r" | 171 | r" |
149 | use std::{fmt::{Debug, Display}}; | 172 | use std::{fmt<|>::{Debug, Display}}; |
150 | ", | 173 | ", |
151 | ) | 174 | ); |
175 | check_assist( | ||
176 | merge_imports, | ||
177 | r" | ||
178 | use std::{fmt::Debug, fmt<|>::Display}; | ||
179 | ", | ||
180 | r" | ||
181 | use std::{fmt<|>::{Display, Debug}}; | ||
182 | ", | ||
183 | ); | ||
152 | } | 184 | } |
153 | } | 185 | } |