Skip to content

Commit e9443b6

Browse files
committed
update merge_import to use editor variant of merge_import methods
1 parent e5635cf commit e9443b6

1 file changed

Lines changed: 61 additions & 81 deletions

File tree

crates/ide-assists/src/handlers/merge_imports.rs

Lines changed: 61 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
use either::Either;
21
use ide_db::imports::{
32
insert_use::{ImportGranularity, InsertUseConfig},
43
merge_imports::{MergeBehavior, try_merge_imports, try_merge_trees},
54
};
65
use syntax::{
7-
AstNode, SyntaxElement, SyntaxNode, algo::neighbor, ast, match_ast, syntax_editor::Removable,
6+
AstNode, SyntaxElement,
7+
algo::neighbor,
8+
ast, match_ast,
9+
syntax_editor::{Removable, SyntaxEditor},
810
};
911

1012
use crate::{
@@ -13,8 +15,6 @@ use crate::{
1315
utils::next_prev,
1416
};
1517

16-
use Edit::*;
17-
1818
// Assist: merge_imports
1919
//
2020
// Merges neighbor imports with a common prefix.
@@ -28,16 +28,19 @@ use Edit::*;
2828
// use std::{fmt::Formatter, io};
2929
// ```
3030
pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> {
31-
let (target, edits) = if ctx.has_empty_selection() {
31+
let (target, editor) = if ctx.has_empty_selection() {
3232
// Merge a neighbor
3333
cov_mark::hit!(merge_with_use_item_neighbors);
3434
let tree = ctx.find_node_at_offset::<ast::UseTree>()?.top_use_tree();
3535
let target = tree.syntax().text_range();
3636

3737
let use_item = tree.syntax().parent().and_then(ast::Use::cast)?;
38-
let mut neighbor = next_prev().find_map(|dir| neighbor(&use_item, dir)).into_iter();
39-
let edits = use_item.try_merge_from(&mut neighbor, &ctx.config.insert_use);
40-
(target, edits?)
38+
let neighbor = next_prev().find_map(|dir| neighbor(&use_item, dir))?;
39+
let parent_node = use_item.syntax().parent()?;
40+
let (editor, _) =
41+
SyntaxEditor::new(parent_node.ancestors().last().unwrap_or(parent_node.clone()));
42+
merge_uses(use_item, vec![neighbor], &ctx.config.insert_use, &editor)?;
43+
(target, editor)
4144
} else {
4245
// Merge selected
4346
let selection_range = ctx.selection_trimmed();
@@ -50,104 +53,81 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> O
5053
});
5154

5255
let first_selected = selected_nodes.next()?;
53-
let edits = match_ast! {
56+
let (editor, _) =
57+
SyntaxEditor::new(parent_node.ancestors().last().unwrap_or(parent_node.clone()));
58+
match_ast! {
5459
match first_selected {
5560
ast::Use(use_item) => {
5661
cov_mark::hit!(merge_with_selected_use_item_neighbors);
57-
use_item.try_merge_from(&mut selected_nodes.filter_map(ast::Use::cast), &ctx.config.insert_use)
62+
merge_uses(
63+
use_item,
64+
selected_nodes.filter_map(ast::Use::cast).collect(),
65+
&ctx.config.insert_use,
66+
&editor,
67+
)?;
5868
},
5969
ast::UseTree(use_tree) => {
6070
cov_mark::hit!(merge_with_selected_use_tree_neighbors);
61-
use_tree.try_merge_from(&mut selected_nodes.filter_map(ast::UseTree::cast), &ctx.config.insert_use)
71+
merge_use_trees(
72+
use_tree,
73+
selected_nodes.filter_map(ast::UseTree::cast).collect(),
74+
&editor,
75+
)?;
6276
},
6377
_ => return None,
6478
}
65-
};
66-
(selection_range, edits?)
67-
};
68-
69-
let parent_node = match ctx.covering_element() {
70-
SyntaxElement::Node(n) => n,
71-
SyntaxElement::Token(t) => t.parent()?,
79+
}
80+
(selection_range, editor)
7281
};
7382

7483
acc.add(AssistId::refactor_rewrite("merge_imports"), "Merge imports", target, |builder| {
75-
let editor = builder.make_editor(&parent_node);
76-
77-
for edit in edits {
78-
match edit {
79-
Remove(it) => {
80-
let node = it.as_ref();
81-
if let Some(left) = node.left() {
82-
left.remove(&editor);
83-
} else if let Some(right) = node.right() {
84-
right.remove(&editor);
85-
}
86-
}
87-
Replace(old, new) => {
88-
editor.replace(old, &new);
89-
}
90-
}
91-
}
9284
builder.add_file_edits(ctx.vfs_file_id(), editor);
9385
})
9486
}
9587

96-
trait Merge: AstNode + Clone {
97-
fn try_merge_from(
98-
self,
99-
items: &mut dyn Iterator<Item = Self>,
100-
cfg: &InsertUseConfig,
101-
) -> Option<Vec<Edit>> {
102-
let mut edits = Vec::new();
103-
let mut merged = self.clone();
104-
for item in items {
105-
merged = merged.try_merge(&item, cfg)?;
106-
edits.push(Edit::Remove(item.into_either()));
107-
}
108-
if !edits.is_empty() {
109-
edits.push(Edit::replace(self, merged));
110-
Some(edits)
111-
} else {
112-
None
113-
}
88+
fn merge_uses(
89+
first: ast::Use,
90+
rest: Vec<ast::Use>,
91+
cfg: &InsertUseConfig,
92+
editor: &SyntaxEditor,
93+
) -> Option<()> {
94+
if rest.is_empty() {
95+
return None;
11496
}
115-
fn try_merge(&self, other: &Self, cfg: &InsertUseConfig) -> Option<Self>;
116-
fn into_either(self) -> Either<ast::Use, ast::UseTree>;
117-
}
11897

119-
impl Merge for ast::Use {
120-
fn try_merge(&self, other: &Self, cfg: &InsertUseConfig) -> Option<Self> {
121-
let mb = match cfg.granularity {
122-
ImportGranularity::One => MergeBehavior::One,
123-
_ => MergeBehavior::Crate,
124-
};
125-
try_merge_imports(self, other, mb)
98+
let mb = match cfg.granularity {
99+
ImportGranularity::One => MergeBehavior::One,
100+
_ => MergeBehavior::Crate,
101+
};
102+
let mut merged = first.clone();
103+
for item in &rest {
104+
merged = try_merge_imports(editor, &merged, item, mb)?;
126105
}
127-
fn into_either(self) -> Either<ast::Use, ast::UseTree> {
128-
Either::Left(self)
106+
for item in rest {
107+
item.remove(editor);
129108
}
109+
editor.replace(first.syntax(), merged.syntax());
110+
Some(())
130111
}
131112

132-
impl Merge for ast::UseTree {
133-
fn try_merge(&self, other: &Self, _: &InsertUseConfig) -> Option<Self> {
134-
try_merge_trees(self, other, MergeBehavior::Crate)
135-
}
136-
fn into_either(self) -> Either<ast::Use, ast::UseTree> {
137-
Either::Right(self)
113+
fn merge_use_trees(
114+
first: ast::UseTree,
115+
rest: Vec<ast::UseTree>,
116+
editor: &SyntaxEditor,
117+
) -> Option<()> {
118+
if rest.is_empty() {
119+
return None;
138120
}
139-
}
140-
141-
#[derive(Debug)]
142-
enum Edit {
143-
Remove(Either<ast::Use, ast::UseTree>),
144-
Replace(SyntaxNode, SyntaxNode),
145-
}
146121

147-
impl Edit {
148-
fn replace(old: impl AstNode, new: impl AstNode) -> Self {
149-
Edit::Replace(old.syntax().clone(), new.syntax().clone())
122+
let mut merged = first.clone();
123+
for item in &rest {
124+
merged = try_merge_trees(editor, &merged, item, MergeBehavior::Crate)?;
125+
}
126+
for item in rest {
127+
item.remove(editor);
150128
}
129+
editor.replace(first.syntax(), merged.syntax());
130+
Some(())
151131
}
152132

153133
#[cfg(test)]

0 commit comments

Comments
 (0)