From 9cbf09ec4f24aa30af1d9855a909a6cfc67188f7 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 18 Mar 2021 12:57:55 +0300 Subject: rewrite merge use trees assist to use muatable syntax trees changelog internal --- crates/syntax/src/ast/edit.rs | 46 ++++++---------------------------- crates/syntax/src/ast/edit_in_place.rs | 44 +++++++++++++++++++++++++++++--- crates/syntax/src/ast/make.rs | 2 +- crates/syntax/src/ted.rs | 28 ++++++++++++++++++--- 4 files changed, 74 insertions(+), 46 deletions(-) (limited to 'crates/syntax/src') diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs index 347862b8a..18820786a 100644 --- a/crates/syntax/src/ast/edit.rs +++ b/crates/syntax/src/ast/edit.rs @@ -9,7 +9,7 @@ use std::{ use arrayvec::ArrayVec; use crate::{ - algo::{self, neighbor, SyntaxRewriter}, + algo::{self, SyntaxRewriter}, ast::{ self, make::{self, tokens}, @@ -322,27 +322,6 @@ impl ast::Use { } self.clone() } - - pub fn remove(&self) -> SyntaxRewriter<'static> { - let mut res = SyntaxRewriter::default(); - res.delete(self.syntax()); - 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() { - res.delete(next_ws.syntax()) - } else { - res.replace(next_ws.syntax(), &make::tokens::whitespace(rest)); - } - } - } - res - } } impl ast::UseTree { @@ -396,22 +375,6 @@ impl ast::UseTree { Some(res) } } - - pub fn remove(&self) -> SyntaxRewriter<'static> { - let mut res = SyntaxRewriter::default(); - res.delete(self.syntax()); - for &dir in [Direction::Next, Direction::Prev].iter() { - if let Some(nb) = neighbor(self, dir) { - self.syntax() - .siblings_with_tokens(dir) - .skip(1) - .take_while(|it| it.as_node() != Some(nb.syntax())) - .for_each(|el| res.delete(&el)); - return res; - } - } - res - } } impl ast::MatchArmList { @@ -592,6 +555,13 @@ impl ops::Add for IndentLevel { } impl IndentLevel { + pub fn from_element(element: &SyntaxElement) -> IndentLevel { + match element { + rowan::NodeOrToken::Node(it) => IndentLevel::from_node(it), + rowan::NodeOrToken::Token(it) => IndentLevel::from_token(it), + } + } + pub fn from_node(node: &SyntaxNode) -> IndentLevel { match node.first_token() { Some(it) => Self::from_token(&it), diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs index b1eed0a2c..529bd0eb1 100644 --- a/crates/syntax/src/ast/edit_in_place.rs +++ b/crates/syntax/src/ast/edit_in_place.rs @@ -2,13 +2,13 @@ use std::iter::empty; -use ast::{edit::AstNodeEdit, make, GenericParamsOwner, WhereClause}; use parser::T; use crate::{ - ast, + algo::neighbor, + ast::{self, edit::AstNodeEdit, make, GenericParamsOwner, WhereClause}, ted::{self, Position}, - AstNode, Direction, + AstNode, AstToken, Direction, }; use super::NameOwner; @@ -126,3 +126,41 @@ impl ast::TypeBoundList { } } } + +impl ast::UseTree { + pub fn remove(&self) { + for &dir in [Direction::Next, Direction::Prev].iter() { + 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())); + ted::remove_all_iter(separators); + break; + } + } + ted::remove(self.syntax()) + } +} + +impl ast::Use { + pub fn remove(&self) { + 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() { + ted::remove(next_ws.syntax()) + } else { + ted::replace(next_ws.syntax(), make::tokens::whitespace(rest)) + } + } + } + ted::remove(self.syntax()) + } +} diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 7049affd9..c08f2c14f 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs @@ -560,7 +560,7 @@ pub mod tokens { pub fn whitespace(text: &str) -> SyntaxToken { assert!(text.trim().is_empty()); let sf = SourceFile::parse(text).ok().unwrap(); - sf.syntax().first_child_or_token().unwrap().into_token().unwrap() + sf.syntax().clone_for_update().first_child_or_token().unwrap().into_token().unwrap() } pub fn doc_comment(text: &str) -> SyntaxToken { diff --git a/crates/syntax/src/ted.rs b/crates/syntax/src/ted.rs index be2b846b1..177d4ff67 100644 --- a/crates/syntax/src/ted.rs +++ b/crates/syntax/src/ted.rs @@ -2,11 +2,14 @@ //! //! The `_raw`-suffixed functions insert elements as is, unsuffixed versions fix //! up elements around the edges. -use std::ops::RangeInclusive; +use std::{mem, ops::RangeInclusive}; use parser::T; -use crate::{ast::make, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken}; +use crate::{ + ast::{edit::IndentLevel, make}, + SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, +}; /// Utility trait to allow calling `ted` functions with references or owned /// nodes. Do not use outside of this module. @@ -101,12 +104,25 @@ pub fn insert_all_raw(position: Position, elements: Vec) { } pub fn remove(elem: impl Element) { - let elem = elem.syntax_element(); - remove_all(elem.clone()..=elem) + elem.syntax_element().detach() } pub fn remove_all(range: RangeInclusive) { replace_all(range, Vec::new()) } +pub fn remove_all_iter(range: impl IntoIterator) { + let mut it = range.into_iter(); + if let Some(mut first) = it.next() { + match it.last() { + Some(mut last) => { + if first.index() > last.index() { + mem::swap(&mut first, &mut last) + } + remove_all(first..=last) + } + None => remove(first), + } + } +} pub fn replace(old: impl Element, new: impl Element) { let old = old.syntax_element(); @@ -149,5 +165,9 @@ fn ws_between(left: &SyntaxElement, right: &SyntaxElement) -> Option