Skip to content

Commit

Permalink
feat: define EditorRemovable trait
Browse files Browse the repository at this point in the history
Signed-off-by: Tarek <[email protected]>
  • Loading branch information
tareknaser committed Nov 6, 2024
1 parent 236168f commit ca0b516
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 15 deletions.
21 changes: 10 additions & 11 deletions crates/ide-assists/src/handlers/merge_imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use ide_db::imports::{
use itertools::Itertools;
use syntax::{
algo::neighbor,
ast::{self, edit_in_place::Removable, syntax_factory::SyntaxFactory},
ast::{self, edit_in_place::EditorRemovable, syntax_factory::SyntaxFactory},
match_ast, AstNode, SyntaxElement, SyntaxNode,
};

Expand Down Expand Up @@ -81,17 +81,16 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio
target,
|builder| {
let mut editor = builder.make_editor(&parent_node);
let edits_mut: Vec<Edit> = edits
.into_iter()
.map(|it| match it {
Remove(Either::Left(it)) => Remove(Either::Left(builder.make_mut(it))),
Remove(Either::Right(it)) => Remove(Either::Right(builder.make_mut(it))),
Replace(old, new) => Replace(builder.make_syntax_mut(old), new),
})
.collect();
for edit in edits_mut {
for edit in edits {
match edit {
Remove(it) => it.as_ref().either(Removable::remove, Removable::remove),
Remove(it) => {
let node = it.as_ref();
if let Some(left) = node.left() {
left.remove(&mut editor);
} else if let Some(right) = node.right() {
right.remove(&mut editor);
}
}
Replace(old, new) => {
editor.replace(old, &new);

Expand Down
72 changes: 69 additions & 3 deletions crates/syntax/src/ast/edit_in_place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ use parser::{SyntaxKind, T};

use crate::{
algo::{self, neighbor},
ast::{self, edit::IndentLevel, make, HasGenericArgs, HasGenericParams},
ast::{
self, edit::IndentLevel, make, syntax_factory::SyntaxFactory, HasGenericArgs,
HasGenericParams,
},
syntax_editor::SyntaxEditor,
ted::{self, Position},
AstNode, AstToken, Direction, SyntaxElement,
SyntaxKind::{ATTR, COMMENT, WHITESPACE},
Expand Down Expand Up @@ -385,6 +389,10 @@ pub trait Removable: AstNode {
fn remove(&self);
}

pub trait EditorRemovable: AstNode {
fn remove(&self, editor: &mut SyntaxEditor);
}

impl Removable for ast::TypeBoundList {
fn remove(&self) {
match self.syntax().siblings_with_tokens(Direction::Prev).find(|it| it.kind() == T![:]) {
Expand Down Expand Up @@ -439,16 +447,35 @@ impl Removable for ast::UseTree {
}
}

impl EditorRemovable for ast::UseTree {
fn remove(&self, editor: &mut SyntaxEditor) {
for dir in [Direction::Next, Direction::Prev] {
if let Some(next_use_tree) = neighbor(self, dir) {
let separators = self
.syntax()
.siblings_with_tokens(dir)
.skip(1)
.take_while(|it| it.as_node() != Some(next_use_tree.syntax()));
for sep in separators {
editor.delete(sep);
}
break;
}
}
editor.delete(self.syntax());
}
}

impl ast::UseTree {
/// Deletes the usetree node represented by the input. Recursively removes parents, including use nodes that become empty.
pub fn remove_recursive(self) {
let parent = self.syntax().parent();

self.remove();
Removable::remove(&self);

if let Some(u) = parent.clone().and_then(ast::Use::cast) {
if u.use_tree().is_none() {
u.remove();
Removable::remove(&u);
}
} else if let Some(u) = parent.and_then(ast::UseTreeList::cast) {
if u.use_trees().next().is_none() {
Expand Down Expand Up @@ -616,6 +643,45 @@ impl Removable for ast::Use {
}
}

impl EditorRemovable for ast::Use {
fn remove(&self, editor: &mut SyntaxEditor) {
let make = SyntaxFactory::new();

let next_ws = self
.syntax()
.next_sibling_or_token()
.and_then(|it| it.into_token())
.and_then(ast::Whitespace::cast);
if let Some(next_ws) = next_ws {
let ws_text = next_ws.syntax().text();
if let Some(rest) = ws_text.strip_prefix('\n') {
if rest.is_empty() {
editor.delete(next_ws.syntax());
} else {
editor.replace(next_ws.syntax(), make.whitespace(rest));
}
}
}
let prev_ws = self
.syntax()
.prev_sibling_or_token()
.and_then(|it| it.into_token())
.and_then(ast::Whitespace::cast);
if let Some(prev_ws) = prev_ws {
let ws_text = prev_ws.syntax().text();
let prev_newline = ws_text.rfind('\n').map(|x| x + 1).unwrap_or(0);
let rest = &ws_text[0..prev_newline];
if rest.is_empty() {
editor.delete(prev_ws.syntax());
} else {
editor.replace(prev_ws.syntax(), make.whitespace(rest));
}
}

editor.delete(self.syntax());
}
}

impl ast::Impl {
pub fn get_or_create_assoc_item_list(&self) -> ast::AssocItemList {
if self.assoc_item_list().is_none() {
Expand Down
6 changes: 5 additions & 1 deletion crates/syntax/src/ast/syntax_factory/constructors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use itertools::Itertools;
use crate::{
ast::{self, make, HasName},
syntax_editor::SyntaxMappingBuilder,
AstNode,
AstNode, SyntaxToken,
};

use super::SyntaxFactory;
Expand All @@ -14,6 +14,10 @@ impl SyntaxFactory {
make::name(name).clone_for_update()
}

pub fn whitespace(&self, text: &str) -> SyntaxToken {
make::tokens::whitespace(text)
}

pub fn ident_pat(&self, ref_: bool, mut_: bool, name: ast::Name) -> ast::IdentPat {
let ast = make::ident_pat(ref_, mut_, name.clone()).clone_for_update();

Expand Down

0 comments on commit ca0b516

Please sign in to comment.