diff options
Diffstat (limited to 'crates/syntax/src')
-rw-r--r-- | crates/syntax/src/algo.rs | 19 | ||||
-rw-r--r-- | crates/syntax/src/ast/make.rs | 27 | ||||
-rw-r--r-- | crates/syntax/src/ast/node_ext.rs | 22 | ||||
-rw-r--r-- | crates/syntax/src/ted.rs | 17 |
4 files changed, 66 insertions, 19 deletions
diff --git a/crates/syntax/src/algo.rs b/crates/syntax/src/algo.rs index a153a9e1c..c9229c4e0 100644 --- a/crates/syntax/src/algo.rs +++ b/crates/syntax/src/algo.rs | |||
@@ -342,10 +342,10 @@ enum InsertPos { | |||
342 | 342 | ||
343 | #[derive(Default)] | 343 | #[derive(Default)] |
344 | pub struct SyntaxRewriter<'a> { | 344 | pub struct SyntaxRewriter<'a> { |
345 | f: Option<Box<dyn Fn(&SyntaxElement) -> Option<SyntaxElement> + 'a>>, | ||
346 | //FIXME: add debug_assertions that all elements are in fact from the same file. | 345 | //FIXME: add debug_assertions that all elements are in fact from the same file. |
347 | replacements: FxHashMap<SyntaxElement, Replacement>, | 346 | replacements: FxHashMap<SyntaxElement, Replacement>, |
348 | insertions: IndexMap<InsertPos, Vec<SyntaxElement>>, | 347 | insertions: IndexMap<InsertPos, Vec<SyntaxElement>>, |
348 | _pd: std::marker::PhantomData<&'a ()>, | ||
349 | } | 349 | } |
350 | 350 | ||
351 | impl fmt::Debug for SyntaxRewriter<'_> { | 351 | impl fmt::Debug for SyntaxRewriter<'_> { |
@@ -357,14 +357,7 @@ impl fmt::Debug for SyntaxRewriter<'_> { | |||
357 | } | 357 | } |
358 | } | 358 | } |
359 | 359 | ||
360 | impl<'a> SyntaxRewriter<'a> { | 360 | impl SyntaxRewriter<'_> { |
361 | pub fn from_fn(f: impl Fn(&SyntaxElement) -> Option<SyntaxElement> + 'a) -> SyntaxRewriter<'a> { | ||
362 | SyntaxRewriter { | ||
363 | f: Some(Box::new(f)), | ||
364 | replacements: FxHashMap::default(), | ||
365 | insertions: IndexMap::default(), | ||
366 | } | ||
367 | } | ||
368 | pub fn delete<T: Clone + Into<SyntaxElement>>(&mut self, what: &T) { | 361 | pub fn delete<T: Clone + Into<SyntaxElement>>(&mut self, what: &T) { |
369 | let what = what.clone().into(); | 362 | let what = what.clone().into(); |
370 | let replacement = Replacement::Delete; | 363 | let replacement = Replacement::Delete; |
@@ -470,7 +463,7 @@ impl<'a> SyntaxRewriter<'a> { | |||
470 | pub fn rewrite(&self, node: &SyntaxNode) -> SyntaxNode { | 463 | pub fn rewrite(&self, node: &SyntaxNode) -> SyntaxNode { |
471 | let _p = profile::span("rewrite"); | 464 | let _p = profile::span("rewrite"); |
472 | 465 | ||
473 | if self.f.is_none() && self.replacements.is_empty() && self.insertions.is_empty() { | 466 | if self.replacements.is_empty() && self.insertions.is_empty() { |
474 | return node.clone(); | 467 | return node.clone(); |
475 | } | 468 | } |
476 | let green = self.rewrite_children(node); | 469 | let green = self.rewrite_children(node); |
@@ -495,7 +488,6 @@ impl<'a> SyntaxRewriter<'a> { | |||
495 | } | 488 | } |
496 | } | 489 | } |
497 | 490 | ||
498 | assert!(self.f.is_none()); | ||
499 | self.replacements | 491 | self.replacements |
500 | .keys() | 492 | .keys() |
501 | .filter_map(element_to_node_or_parent) | 493 | .filter_map(element_to_node_or_parent) |
@@ -510,10 +502,6 @@ impl<'a> SyntaxRewriter<'a> { | |||
510 | } | 502 | } |
511 | 503 | ||
512 | fn replacement(&self, element: &SyntaxElement) -> Option<Replacement> { | 504 | fn replacement(&self, element: &SyntaxElement) -> Option<Replacement> { |
513 | if let Some(f) = &self.f { | ||
514 | assert!(self.replacements.is_empty()); | ||
515 | return f(element).map(Replacement::Single); | ||
516 | } | ||
517 | self.replacements.get(element).cloned() | 505 | self.replacements.get(element).cloned() |
518 | } | 506 | } |
519 | 507 | ||
@@ -574,7 +562,6 @@ fn element_to_green(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, row | |||
574 | 562 | ||
575 | impl ops::AddAssign for SyntaxRewriter<'_> { | 563 | impl ops::AddAssign for SyntaxRewriter<'_> { |
576 | fn add_assign(&mut self, rhs: SyntaxRewriter) { | 564 | fn add_assign(&mut self, rhs: SyntaxRewriter) { |
577 | assert!(rhs.f.is_none()); | ||
578 | self.replacements.extend(rhs.replacements); | 565 | self.replacements.extend(rhs.replacements); |
579 | for (pos, insertions) in rhs.insertions.into_iter() { | 566 | for (pos, insertions) in rhs.insertions.into_iter() { |
580 | match self.insertions.entry(pos) { | 567 | match self.insertions.entry(pos) { |
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 4cf6f871e..42da09606 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs | |||
@@ -137,6 +137,17 @@ pub fn use_(visibility: Option<ast::Visibility>, use_tree: ast::UseTree) -> ast: | |||
137 | ast_from_text(&format!("{}use {};", visibility, use_tree)) | 137 | ast_from_text(&format!("{}use {};", visibility, use_tree)) |
138 | } | 138 | } |
139 | 139 | ||
140 | pub fn record_expr(path: ast::Path, fields: ast::RecordExprFieldList) -> ast::RecordExpr { | ||
141 | ast_from_text(&format!("fn f() {{ {} {} }}", path, fields)) | ||
142 | } | ||
143 | |||
144 | pub fn record_expr_field_list( | ||
145 | fields: impl IntoIterator<Item = ast::RecordExprField>, | ||
146 | ) -> ast::RecordExprFieldList { | ||
147 | let fields = fields.into_iter().join(", "); | ||
148 | ast_from_text(&format!("fn f() {{ S {{ {} }} }}", fields)) | ||
149 | } | ||
150 | |||
140 | pub fn record_expr_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordExprField { | 151 | pub fn record_expr_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordExprField { |
141 | return match expr { | 152 | return match expr { |
142 | Some(expr) => from_text(&format!("{}: {}", name, expr)), | 153 | Some(expr) => from_text(&format!("{}: {}", name, expr)), |
@@ -339,6 +350,21 @@ pub fn record_pat(path: ast::Path, pats: impl IntoIterator<Item = ast::Pat>) -> | |||
339 | } | 350 | } |
340 | } | 351 | } |
341 | 352 | ||
353 | pub fn record_pat_with_fields(path: ast::Path, fields: ast::RecordPatFieldList) -> ast::RecordPat { | ||
354 | ast_from_text(&format!("fn f({} {}: ()))", path, fields)) | ||
355 | } | ||
356 | |||
357 | pub fn record_pat_field_list( | ||
358 | fields: impl IntoIterator<Item = ast::RecordPatField>, | ||
359 | ) -> ast::RecordPatFieldList { | ||
360 | let fields = fields.into_iter().join(", "); | ||
361 | ast_from_text(&format!("fn f(S {{ {} }}: ()))", fields)) | ||
362 | } | ||
363 | |||
364 | pub fn record_pat_field(name_ref: ast::NameRef, pat: ast::Pat) -> ast::RecordPatField { | ||
365 | ast_from_text(&format!("fn f(S {{ {}: {} }}: ()))", name_ref, pat)) | ||
366 | } | ||
367 | |||
342 | /// Returns a `BindPat` if the path has just one segment, a `PathPat` otherwise. | 368 | /// Returns a `BindPat` if the path has just one segment, a `PathPat` otherwise. |
343 | pub fn path_pat(path: ast::Path) -> ast::Pat { | 369 | pub fn path_pat(path: ast::Path) -> ast::Pat { |
344 | return from_text(&path.to_string()); | 370 | return from_text(&path.to_string()); |
@@ -606,6 +632,7 @@ pub mod tokens { | |||
606 | SOURCE_FILE | 632 | SOURCE_FILE |
607 | .tree() | 633 | .tree() |
608 | .syntax() | 634 | .syntax() |
635 | .clone_for_update() | ||
609 | .descendants_with_tokens() | 636 | .descendants_with_tokens() |
610 | .filter_map(|it| it.into_token()) | 637 | .filter_map(|it| it.into_token()) |
611 | .find(|it| it.kind() == WHITESPACE && it.text() == "\n\n") | 638 | .find(|it| it.kind() == WHITESPACE && it.text() == "\n\n") |
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index 171099661..492fbc4a0 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! Various extension methods to ast Nodes, which are hard to code-generate. | 1 | //! Various extension methods to ast Nodes, which are hard to code-generate. |
2 | //! Extensions for various expressions live in a sibling `expr_extensions` module. | 2 | //! Extensions for various expressions live in a sibling `expr_extensions` module. |
3 | 3 | ||
4 | use std::fmt; | 4 | use std::{fmt, iter::successors}; |
5 | 5 | ||
6 | use itertools::Itertools; | 6 | use itertools::Itertools; |
7 | use parser::SyntaxKind; | 7 | use parser::SyntaxKind; |
@@ -237,6 +237,26 @@ impl ast::Path { | |||
237 | None => self.segment(), | 237 | None => self.segment(), |
238 | } | 238 | } |
239 | } | 239 | } |
240 | |||
241 | pub fn first_qualifier_or_self(&self) -> ast::Path { | ||
242 | successors(Some(self.clone()), ast::Path::qualifier).last().unwrap() | ||
243 | } | ||
244 | |||
245 | pub fn first_segment(&self) -> Option<ast::PathSegment> { | ||
246 | self.first_qualifier_or_self().segment() | ||
247 | } | ||
248 | |||
249 | pub fn segments(&self) -> impl Iterator<Item = ast::PathSegment> + Clone { | ||
250 | // cant make use of SyntaxNode::siblings, because the returned Iterator is not clone | ||
251 | successors(self.first_segment(), |p| { | ||
252 | p.parent_path().parent_path().and_then(|p| p.segment()) | ||
253 | }) | ||
254 | } | ||
255 | } | ||
256 | impl ast::UseTree { | ||
257 | pub fn is_simple_path(&self) -> bool { | ||
258 | self.use_tree_list().is_none() && self.star_token().is_none() | ||
259 | } | ||
240 | } | 260 | } |
241 | 261 | ||
242 | impl ast::UseTreeList { | 262 | impl ast::UseTreeList { |
diff --git a/crates/syntax/src/ted.rs b/crates/syntax/src/ted.rs index 450f2e447..91a06101f 100644 --- a/crates/syntax/src/ted.rs +++ b/crates/syntax/src/ted.rs | |||
@@ -7,7 +7,7 @@ use std::{mem, ops::RangeInclusive}; | |||
7 | use parser::T; | 7 | use parser::T; |
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{ |
10 | ast::{edit::IndentLevel, make}, | 10 | ast::{self, edit::IndentLevel, make, AstNode}, |
11 | SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, | 11 | SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, |
12 | }; | 12 | }; |
13 | 13 | ||
@@ -147,6 +147,16 @@ pub fn append_child_raw(node: &(impl Into<SyntaxNode> + Clone), child: impl Elem | |||
147 | fn ws_before(position: &Position, new: &SyntaxElement) -> Option<SyntaxToken> { | 147 | fn ws_before(position: &Position, new: &SyntaxElement) -> Option<SyntaxToken> { |
148 | let prev = match &position.repr { | 148 | let prev = match &position.repr { |
149 | PositionRepr::FirstChild(_) => return None, | 149 | PositionRepr::FirstChild(_) => return None, |
150 | PositionRepr::After(it) if it.kind() == SyntaxKind::L_CURLY => { | ||
151 | if new.kind() == SyntaxKind::USE { | ||
152 | if let Some(item_list) = it.parent().and_then(ast::ItemList::cast) { | ||
153 | let mut indent = IndentLevel::from_element(&item_list.syntax().clone().into()); | ||
154 | indent.0 += 1; | ||
155 | return Some(make::tokens::whitespace(&format!("\n{}", indent))); | ||
156 | } | ||
157 | } | ||
158 | it | ||
159 | } | ||
150 | PositionRepr::After(it) => it, | 160 | PositionRepr::After(it) => it, |
151 | }; | 161 | }; |
152 | ws_between(prev, new) | 162 | ws_between(prev, new) |
@@ -173,7 +183,10 @@ fn ws_between(left: &SyntaxElement, right: &SyntaxElement) -> Option<SyntaxToken | |||
173 | } | 183 | } |
174 | 184 | ||
175 | if right.kind() == SyntaxKind::USE { | 185 | if right.kind() == SyntaxKind::USE { |
176 | let indent = IndentLevel::from_element(left); | 186 | let mut indent = IndentLevel::from_element(left); |
187 | if left.kind() == SyntaxKind::USE { | ||
188 | indent.0 = IndentLevel::from_element(right).0.max(indent.0); | ||
189 | } | ||
177 | return Some(make::tokens::whitespace(&format!("\n{}", indent))); | 190 | return Some(make::tokens::whitespace(&format!("\n{}", indent))); |
178 | } | 191 | } |
179 | Some(make::tokens::single_space()) | 192 | Some(make::tokens::single_space()) |