diff options
author | Aleksey Kladov <[email protected]> | 2021-03-18 09:57:55 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2021-03-22 17:47:46 +0000 |
commit | 9cbf09ec4f24aa30af1d9855a909a6cfc67188f7 (patch) | |
tree | 20057e98e523440ebc3120e1e3c104b306a97baf /crates/syntax | |
parent | d834306e7cf85fe0b07e4979d2ff39bf4ef1f6be (diff) |
rewrite merge use trees assist to use muatable syntax trees
changelog internal
Diffstat (limited to 'crates/syntax')
-rw-r--r-- | crates/syntax/src/ast/edit.rs | 46 | ||||
-rw-r--r-- | crates/syntax/src/ast/edit_in_place.rs | 44 | ||||
-rw-r--r-- | crates/syntax/src/ast/make.rs | 2 | ||||
-rw-r--r-- | crates/syntax/src/ted.rs | 28 |
4 files changed, 74 insertions, 46 deletions
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::{ | |||
9 | use arrayvec::ArrayVec; | 9 | use arrayvec::ArrayVec; |
10 | 10 | ||
11 | use crate::{ | 11 | use crate::{ |
12 | algo::{self, neighbor, SyntaxRewriter}, | 12 | algo::{self, SyntaxRewriter}, |
13 | ast::{ | 13 | ast::{ |
14 | self, | 14 | self, |
15 | make::{self, tokens}, | 15 | make::{self, tokens}, |
@@ -322,27 +322,6 @@ impl ast::Use { | |||
322 | } | 322 | } |
323 | self.clone() | 323 | self.clone() |
324 | } | 324 | } |
325 | |||
326 | pub fn remove(&self) -> SyntaxRewriter<'static> { | ||
327 | let mut res = SyntaxRewriter::default(); | ||
328 | res.delete(self.syntax()); | ||
329 | let next_ws = self | ||
330 | .syntax() | ||
331 | .next_sibling_or_token() | ||
332 | .and_then(|it| it.into_token()) | ||
333 | .and_then(ast::Whitespace::cast); | ||
334 | if let Some(next_ws) = next_ws { | ||
335 | let ws_text = next_ws.syntax().text(); | ||
336 | if let Some(rest) = ws_text.strip_prefix('\n') { | ||
337 | if rest.is_empty() { | ||
338 | res.delete(next_ws.syntax()) | ||
339 | } else { | ||
340 | res.replace(next_ws.syntax(), &make::tokens::whitespace(rest)); | ||
341 | } | ||
342 | } | ||
343 | } | ||
344 | res | ||
345 | } | ||
346 | } | 325 | } |
347 | 326 | ||
348 | impl ast::UseTree { | 327 | impl ast::UseTree { |
@@ -396,22 +375,6 @@ impl ast::UseTree { | |||
396 | Some(res) | 375 | Some(res) |
397 | } | 376 | } |
398 | } | 377 | } |
399 | |||
400 | pub fn remove(&self) -> SyntaxRewriter<'static> { | ||
401 | let mut res = SyntaxRewriter::default(); | ||
402 | res.delete(self.syntax()); | ||
403 | for &dir in [Direction::Next, Direction::Prev].iter() { | ||
404 | if let Some(nb) = neighbor(self, dir) { | ||
405 | self.syntax() | ||
406 | .siblings_with_tokens(dir) | ||
407 | .skip(1) | ||
408 | .take_while(|it| it.as_node() != Some(nb.syntax())) | ||
409 | .for_each(|el| res.delete(&el)); | ||
410 | return res; | ||
411 | } | ||
412 | } | ||
413 | res | ||
414 | } | ||
415 | } | 378 | } |
416 | 379 | ||
417 | impl ast::MatchArmList { | 380 | impl ast::MatchArmList { |
@@ -592,6 +555,13 @@ impl ops::Add<u8> for IndentLevel { | |||
592 | } | 555 | } |
593 | 556 | ||
594 | impl IndentLevel { | 557 | impl IndentLevel { |
558 | pub fn from_element(element: &SyntaxElement) -> IndentLevel { | ||
559 | match element { | ||
560 | rowan::NodeOrToken::Node(it) => IndentLevel::from_node(it), | ||
561 | rowan::NodeOrToken::Token(it) => IndentLevel::from_token(it), | ||
562 | } | ||
563 | } | ||
564 | |||
595 | pub fn from_node(node: &SyntaxNode) -> IndentLevel { | 565 | pub fn from_node(node: &SyntaxNode) -> IndentLevel { |
596 | match node.first_token() { | 566 | match node.first_token() { |
597 | Some(it) => Self::from_token(&it), | 567 | 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 @@ | |||
2 | 2 | ||
3 | use std::iter::empty; | 3 | use std::iter::empty; |
4 | 4 | ||
5 | use ast::{edit::AstNodeEdit, make, GenericParamsOwner, WhereClause}; | ||
6 | use parser::T; | 5 | use parser::T; |
7 | 6 | ||
8 | use crate::{ | 7 | use crate::{ |
9 | ast, | 8 | algo::neighbor, |
9 | ast::{self, edit::AstNodeEdit, make, GenericParamsOwner, WhereClause}, | ||
10 | ted::{self, Position}, | 10 | ted::{self, Position}, |
11 | AstNode, Direction, | 11 | AstNode, AstToken, Direction, |
12 | }; | 12 | }; |
13 | 13 | ||
14 | use super::NameOwner; | 14 | use super::NameOwner; |
@@ -126,3 +126,41 @@ impl ast::TypeBoundList { | |||
126 | } | 126 | } |
127 | } | 127 | } |
128 | } | 128 | } |
129 | |||
130 | impl ast::UseTree { | ||
131 | pub fn remove(&self) { | ||
132 | for &dir in [Direction::Next, Direction::Prev].iter() { | ||
133 | if let Some(next_use_tree) = neighbor(self, dir) { | ||
134 | let separators = self | ||
135 | .syntax() | ||
136 | .siblings_with_tokens(dir) | ||
137 | .skip(1) | ||
138 | .take_while(|it| it.as_node() != Some(next_use_tree.syntax())); | ||
139 | ted::remove_all_iter(separators); | ||
140 | break; | ||
141 | } | ||
142 | } | ||
143 | ted::remove(self.syntax()) | ||
144 | } | ||
145 | } | ||
146 | |||
147 | impl ast::Use { | ||
148 | pub fn remove(&self) { | ||
149 | let next_ws = self | ||
150 | .syntax() | ||
151 | .next_sibling_or_token() | ||
152 | .and_then(|it| it.into_token()) | ||
153 | .and_then(ast::Whitespace::cast); | ||
154 | if let Some(next_ws) = next_ws { | ||
155 | let ws_text = next_ws.syntax().text(); | ||
156 | if let Some(rest) = ws_text.strip_prefix('\n') { | ||
157 | if rest.is_empty() { | ||
158 | ted::remove(next_ws.syntax()) | ||
159 | } else { | ||
160 | ted::replace(next_ws.syntax(), make::tokens::whitespace(rest)) | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | ted::remove(self.syntax()) | ||
165 | } | ||
166 | } | ||
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 { | |||
560 | pub fn whitespace(text: &str) -> SyntaxToken { | 560 | pub fn whitespace(text: &str) -> SyntaxToken { |
561 | assert!(text.trim().is_empty()); | 561 | assert!(text.trim().is_empty()); |
562 | let sf = SourceFile::parse(text).ok().unwrap(); | 562 | let sf = SourceFile::parse(text).ok().unwrap(); |
563 | sf.syntax().first_child_or_token().unwrap().into_token().unwrap() | 563 | sf.syntax().clone_for_update().first_child_or_token().unwrap().into_token().unwrap() |
564 | } | 564 | } |
565 | 565 | ||
566 | pub fn doc_comment(text: &str) -> SyntaxToken { | 566 | 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 @@ | |||
2 | //! | 2 | //! |
3 | //! The `_raw`-suffixed functions insert elements as is, unsuffixed versions fix | 3 | //! The `_raw`-suffixed functions insert elements as is, unsuffixed versions fix |
4 | //! up elements around the edges. | 4 | //! up elements around the edges. |
5 | use std::ops::RangeInclusive; | 5 | use std::{mem, ops::RangeInclusive}; |
6 | 6 | ||
7 | use parser::T; | 7 | use parser::T; |
8 | 8 | ||
9 | use crate::{ast::make, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken}; | 9 | use crate::{ |
10 | ast::{edit::IndentLevel, make}, | ||
11 | SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, | ||
12 | }; | ||
10 | 13 | ||
11 | /// Utility trait to allow calling `ted` functions with references or owned | 14 | /// Utility trait to allow calling `ted` functions with references or owned |
12 | /// nodes. Do not use outside of this module. | 15 | /// nodes. Do not use outside of this module. |
@@ -101,12 +104,25 @@ pub fn insert_all_raw(position: Position, elements: Vec<SyntaxElement>) { | |||
101 | } | 104 | } |
102 | 105 | ||
103 | pub fn remove(elem: impl Element) { | 106 | pub fn remove(elem: impl Element) { |
104 | let elem = elem.syntax_element(); | 107 | elem.syntax_element().detach() |
105 | remove_all(elem.clone()..=elem) | ||
106 | } | 108 | } |
107 | pub fn remove_all(range: RangeInclusive<SyntaxElement>) { | 109 | pub fn remove_all(range: RangeInclusive<SyntaxElement>) { |
108 | replace_all(range, Vec::new()) | 110 | replace_all(range, Vec::new()) |
109 | } | 111 | } |
112 | pub fn remove_all_iter(range: impl IntoIterator<Item = SyntaxElement>) { | ||
113 | let mut it = range.into_iter(); | ||
114 | if let Some(mut first) = it.next() { | ||
115 | match it.last() { | ||
116 | Some(mut last) => { | ||
117 | if first.index() > last.index() { | ||
118 | mem::swap(&mut first, &mut last) | ||
119 | } | ||
120 | remove_all(first..=last) | ||
121 | } | ||
122 | None => remove(first), | ||
123 | } | ||
124 | } | ||
125 | } | ||
110 | 126 | ||
111 | pub fn replace(old: impl Element, new: impl Element) { | 127 | pub fn replace(old: impl Element, new: impl Element) { |
112 | let old = old.syntax_element(); | 128 | let old = old.syntax_element(); |
@@ -149,5 +165,9 @@ fn ws_between(left: &SyntaxElement, right: &SyntaxElement) -> Option<SyntaxToken | |||
149 | if right.kind() == T![;] || right.kind() == T![,] { | 165 | if right.kind() == T![;] || right.kind() == T![,] { |
150 | return None; | 166 | return None; |
151 | } | 167 | } |
168 | if right.kind() == SyntaxKind::USE { | ||
169 | let indent = IndentLevel::from_element(left); | ||
170 | return Some(make::tokens::whitespace(&format!("\n{}", indent))); | ||
171 | } | ||
152 | Some(make::tokens::single_space()) | 172 | Some(make::tokens::single_space()) |
153 | } | 173 | } |