Skip to content

Commit ca0b516

Browse files
committed
feat: define EditorRemovable trait
Signed-off-by: Tarek <[email protected]>
1 parent 236168f commit ca0b516

File tree

3 files changed

+84
-15
lines changed

3 files changed

+84
-15
lines changed

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

+10-11
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use ide_db::imports::{
66
use itertools::Itertools;
77
use syntax::{
88
algo::neighbor,
9-
ast::{self, edit_in_place::Removable, syntax_factory::SyntaxFactory},
9+
ast::{self, edit_in_place::EditorRemovable, syntax_factory::SyntaxFactory},
1010
match_ast, AstNode, SyntaxElement, SyntaxNode,
1111
};
1212

@@ -81,17 +81,16 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio
8181
target,
8282
|builder| {
8383
let mut editor = builder.make_editor(&parent_node);
84-
let edits_mut: Vec<Edit> = edits
85-
.into_iter()
86-
.map(|it| match it {
87-
Remove(Either::Left(it)) => Remove(Either::Left(builder.make_mut(it))),
88-
Remove(Either::Right(it)) => Remove(Either::Right(builder.make_mut(it))),
89-
Replace(old, new) => Replace(builder.make_syntax_mut(old), new),
90-
})
91-
.collect();
92-
for edit in edits_mut {
84+
for edit in edits {
9385
match edit {
94-
Remove(it) => it.as_ref().either(Removable::remove, Removable::remove),
86+
Remove(it) => {
87+
let node = it.as_ref();
88+
if let Some(left) = node.left() {
89+
left.remove(&mut editor);
90+
} else if let Some(right) = node.right() {
91+
right.remove(&mut editor);
92+
}
93+
}
9594
Replace(old, new) => {
9695
editor.replace(old, &new);
9796

crates/syntax/src/ast/edit_in_place.rs

+69-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ use parser::{SyntaxKind, T};
66

77
use crate::{
88
algo::{self, neighbor},
9-
ast::{self, edit::IndentLevel, make, HasGenericArgs, HasGenericParams},
9+
ast::{
10+
self, edit::IndentLevel, make, syntax_factory::SyntaxFactory, HasGenericArgs,
11+
HasGenericParams,
12+
},
13+
syntax_editor::SyntaxEditor,
1014
ted::{self, Position},
1115
AstNode, AstToken, Direction, SyntaxElement,
1216
SyntaxKind::{ATTR, COMMENT, WHITESPACE},
@@ -385,6 +389,10 @@ pub trait Removable: AstNode {
385389
fn remove(&self);
386390
}
387391

392+
pub trait EditorRemovable: AstNode {
393+
fn remove(&self, editor: &mut SyntaxEditor);
394+
}
395+
388396
impl Removable for ast::TypeBoundList {
389397
fn remove(&self) {
390398
match self.syntax().siblings_with_tokens(Direction::Prev).find(|it| it.kind() == T![:]) {
@@ -439,16 +447,35 @@ impl Removable for ast::UseTree {
439447
}
440448
}
441449

450+
impl EditorRemovable for ast::UseTree {
451+
fn remove(&self, editor: &mut SyntaxEditor) {
452+
for dir in [Direction::Next, Direction::Prev] {
453+
if let Some(next_use_tree) = neighbor(self, dir) {
454+
let separators = self
455+
.syntax()
456+
.siblings_with_tokens(dir)
457+
.skip(1)
458+
.take_while(|it| it.as_node() != Some(next_use_tree.syntax()));
459+
for sep in separators {
460+
editor.delete(sep);
461+
}
462+
break;
463+
}
464+
}
465+
editor.delete(self.syntax());
466+
}
467+
}
468+
442469
impl ast::UseTree {
443470
/// Deletes the usetree node represented by the input. Recursively removes parents, including use nodes that become empty.
444471
pub fn remove_recursive(self) {
445472
let parent = self.syntax().parent();
446473

447-
self.remove();
474+
Removable::remove(&self);
448475

449476
if let Some(u) = parent.clone().and_then(ast::Use::cast) {
450477
if u.use_tree().is_none() {
451-
u.remove();
478+
Removable::remove(&u);
452479
}
453480
} else if let Some(u) = parent.and_then(ast::UseTreeList::cast) {
454481
if u.use_trees().next().is_none() {
@@ -616,6 +643,45 @@ impl Removable for ast::Use {
616643
}
617644
}
618645

646+
impl EditorRemovable for ast::Use {
647+
fn remove(&self, editor: &mut SyntaxEditor) {
648+
let make = SyntaxFactory::new();
649+
650+
let next_ws = self
651+
.syntax()
652+
.next_sibling_or_token()
653+
.and_then(|it| it.into_token())
654+
.and_then(ast::Whitespace::cast);
655+
if let Some(next_ws) = next_ws {
656+
let ws_text = next_ws.syntax().text();
657+
if let Some(rest) = ws_text.strip_prefix('\n') {
658+
if rest.is_empty() {
659+
editor.delete(next_ws.syntax());
660+
} else {
661+
editor.replace(next_ws.syntax(), make.whitespace(rest));
662+
}
663+
}
664+
}
665+
let prev_ws = self
666+
.syntax()
667+
.prev_sibling_or_token()
668+
.and_then(|it| it.into_token())
669+
.and_then(ast::Whitespace::cast);
670+
if let Some(prev_ws) = prev_ws {
671+
let ws_text = prev_ws.syntax().text();
672+
let prev_newline = ws_text.rfind('\n').map(|x| x + 1).unwrap_or(0);
673+
let rest = &ws_text[0..prev_newline];
674+
if rest.is_empty() {
675+
editor.delete(prev_ws.syntax());
676+
} else {
677+
editor.replace(prev_ws.syntax(), make.whitespace(rest));
678+
}
679+
}
680+
681+
editor.delete(self.syntax());
682+
}
683+
}
684+
619685
impl ast::Impl {
620686
pub fn get_or_create_assoc_item_list(&self) -> ast::AssocItemList {
621687
if self.assoc_item_list().is_none() {

crates/syntax/src/ast/syntax_factory/constructors.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use itertools::Itertools;
44
use crate::{
55
ast::{self, make, HasName},
66
syntax_editor::SyntaxMappingBuilder,
7-
AstNode,
7+
AstNode, SyntaxToken,
88
};
99

1010
use super::SyntaxFactory;
@@ -14,6 +14,10 @@ impl SyntaxFactory {
1414
make::name(name).clone_for_update()
1515
}
1616

17+
pub fn whitespace(&self, text: &str) -> SyntaxToken {
18+
make::tokens::whitespace(text)
19+
}
20+
1721
pub fn ident_pat(&self, ref_: bool, mut_: bool, name: ast::Name) -> ast::IdentPat {
1822
let ast = make::ident_pat(ref_, mut_, name.clone()).clone_for_update();
1923

0 commit comments

Comments
 (0)