Skip to content

Commit d7539fb

Browse files
committed
update merge_import to use editor variant of merge_import methods
1 parent 072f44f commit d7539fb

1 file changed

Lines changed: 58 additions & 81 deletions

File tree

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

Lines changed: 58 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,17 @@ 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 (editor, _) = SyntaxEditor::new(use_item.syntax().parent()?.ancestors().last()?);
40+
merge_uses(use_item, vec![neighbor], &ctx.config.insert_use, &editor)?;
41+
(target, editor)
4142
} else {
4243
// Merge selected
4344
let selection_range = ctx.selection_trimmed();
@@ -50,104 +51,80 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> O
5051
});
5152

5253
let first_selected = selected_nodes.next()?;
53-
let edits = match_ast! {
54+
let (editor, _) = SyntaxEditor::new(parent_node.ancestors().last().unwrap());
55+
match_ast! {
5456
match first_selected {
5557
ast::Use(use_item) => {
5658
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)
59+
merge_uses(
60+
use_item,
61+
selected_nodes.filter_map(ast::Use::cast).collect(),
62+
&ctx.config.insert_use,
63+
&editor,
64+
)?;
5865
},
5966
ast::UseTree(use_tree) => {
6067
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)
68+
merge_use_trees(
69+
use_tree,
70+
selected_nodes.filter_map(ast::UseTree::cast).collect(),
71+
&editor,
72+
)?;
6273
},
6374
_ => return None,
6475
}
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()?,
76+
}
77+
(selection_range, editor)
7278
};
7379

7480
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-
}
9281
builder.add_file_edits(ctx.vfs_file_id(), editor);
9382
})
9483
}
9584

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-
}
85+
fn merge_uses(
86+
first: ast::Use,
87+
rest: Vec<ast::Use>,
88+
cfg: &InsertUseConfig,
89+
editor: &SyntaxEditor,
90+
) -> Option<()> {
91+
if rest.is_empty() {
92+
return None;
11493
}
115-
fn try_merge(&self, other: &Self, cfg: &InsertUseConfig) -> Option<Self>;
116-
fn into_either(self) -> Either<ast::Use, ast::UseTree>;
117-
}
11894

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)
95+
let mb = match cfg.granularity {
96+
ImportGranularity::One => MergeBehavior::One,
97+
_ => MergeBehavior::Crate,
98+
};
99+
let mut merged = first.clone();
100+
for item in &rest {
101+
merged = try_merge_imports(editor, &merged, item, mb)?;
126102
}
127-
fn into_either(self) -> Either<ast::Use, ast::UseTree> {
128-
Either::Left(self)
103+
for item in rest {
104+
item.remove(editor);
129105
}
106+
editor.replace(first.syntax(), merged.syntax());
107+
Some(())
130108
}
131109

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)
110+
fn merge_use_trees(
111+
first: ast::UseTree,
112+
rest: Vec<ast::UseTree>,
113+
editor: &SyntaxEditor,
114+
) -> Option<()> {
115+
if rest.is_empty() {
116+
return None;
138117
}
139-
}
140-
141-
#[derive(Debug)]
142-
enum Edit {
143-
Remove(Either<ast::Use, ast::UseTree>),
144-
Replace(SyntaxNode, SyntaxNode),
145-
}
146118

147-
impl Edit {
148-
fn replace(old: impl AstNode, new: impl AstNode) -> Self {
149-
Edit::Replace(old.syntax().clone(), new.syntax().clone())
119+
let mut merged = first.clone();
120+
for item in &rest {
121+
merged = try_merge_trees(editor, &merged, item, MergeBehavior::Crate)?;
122+
}
123+
for item in rest {
124+
item.remove(editor);
150125
}
126+
editor.replace(first.syntax(), merged.syntax());
127+
Some(())
151128
}
152129

153130
#[cfg(test)]

0 commit comments

Comments
 (0)