diff options
Diffstat (limited to 'crates/syntax/src')
-rw-r--r-- | crates/syntax/src/algo.rs | 35 | ||||
-rw-r--r-- | crates/syntax/src/ast.rs | 7 | ||||
-rw-r--r-- | crates/syntax/src/ast/edit_in_place.rs | 129 | ||||
-rw-r--r-- | crates/syntax/src/ast/generated/nodes.rs | 10 | ||||
-rw-r--r-- | crates/syntax/src/ast/make.rs | 14 | ||||
-rw-r--r-- | crates/syntax/src/ast/node_ext.rs | 4 | ||||
-rw-r--r-- | crates/syntax/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/syntax/src/parsing/reparsing.rs | 6 | ||||
-rw-r--r-- | crates/syntax/src/ted.rs | 126 |
9 files changed, 305 insertions, 27 deletions
diff --git a/crates/syntax/src/algo.rs b/crates/syntax/src/algo.rs index b13252eec..82ebf9037 100644 --- a/crates/syntax/src/algo.rs +++ b/crates/syntax/src/algo.rs | |||
@@ -4,7 +4,6 @@ use std::{ | |||
4 | fmt, | 4 | fmt, |
5 | hash::BuildHasherDefault, | 5 | hash::BuildHasherDefault, |
6 | ops::{self, RangeInclusive}, | 6 | ops::{self, RangeInclusive}, |
7 | ptr, | ||
8 | }; | 7 | }; |
9 | 8 | ||
10 | use indexmap::IndexMap; | 9 | use indexmap::IndexMap; |
@@ -27,7 +26,7 @@ pub fn ancestors_at_offset( | |||
27 | offset: TextSize, | 26 | offset: TextSize, |
28 | ) -> impl Iterator<Item = SyntaxNode> { | 27 | ) -> impl Iterator<Item = SyntaxNode> { |
29 | node.token_at_offset(offset) | 28 | node.token_at_offset(offset) |
30 | .map(|token| token.parent().ancestors()) | 29 | .map(|token| token.ancestors()) |
31 | .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len()) | 30 | .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len()) |
32 | } | 31 | } |
33 | 32 | ||
@@ -171,7 +170,7 @@ pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff { | |||
171 | && lhs.text_range().len() == rhs.text_range().len() | 170 | && lhs.text_range().len() == rhs.text_range().len() |
172 | && match (&lhs, &rhs) { | 171 | && match (&lhs, &rhs) { |
173 | (NodeOrToken::Node(lhs), NodeOrToken::Node(rhs)) => { | 172 | (NodeOrToken::Node(lhs), NodeOrToken::Node(rhs)) => { |
174 | ptr::eq(lhs.green(), rhs.green()) || lhs.text() == rhs.text() | 173 | lhs == rhs || lhs.text() == rhs.text() |
175 | } | 174 | } |
176 | (NodeOrToken::Token(lhs), NodeOrToken::Token(rhs)) => lhs.text() == rhs.text(), | 175 | (NodeOrToken::Token(lhs), NodeOrToken::Token(rhs)) => lhs.text() == rhs.text(), |
177 | _ => false, | 176 | _ => false, |
@@ -280,9 +279,10 @@ fn _insert_children( | |||
280 | to_green_element(element) | 279 | to_green_element(element) |
281 | }); | 280 | }); |
282 | 281 | ||
283 | let mut old_children = parent.green().children().map(|it| match it { | 282 | let parent_green = parent.green(); |
284 | NodeOrToken::Token(it) => NodeOrToken::Token(it.clone()), | 283 | let mut old_children = parent_green.children().map(|it| match it { |
285 | NodeOrToken::Node(it) => NodeOrToken::Node(it.clone()), | 284 | NodeOrToken::Token(it) => NodeOrToken::Token(it.to_owned()), |
285 | NodeOrToken::Node(it) => NodeOrToken::Node(it.to_owned()), | ||
286 | }); | 286 | }); |
287 | 287 | ||
288 | let new_children = match &position { | 288 | let new_children = match &position { |
@@ -319,9 +319,10 @@ fn _replace_children( | |||
319 | ) -> SyntaxNode { | 319 | ) -> SyntaxNode { |
320 | let start = position_of_child(parent, to_delete.start().clone()); | 320 | let start = position_of_child(parent, to_delete.start().clone()); |
321 | let end = position_of_child(parent, to_delete.end().clone()); | 321 | let end = position_of_child(parent, to_delete.end().clone()); |
322 | let mut old_children = parent.green().children().map(|it| match it { | 322 | let parent_green = parent.green(); |
323 | NodeOrToken::Token(it) => NodeOrToken::Token(it.clone()), | 323 | let mut old_children = parent_green.children().map(|it| match it { |
324 | NodeOrToken::Node(it) => NodeOrToken::Node(it.clone()), | 324 | NodeOrToken::Token(it) => NodeOrToken::Token(it.to_owned()), |
325 | NodeOrToken::Node(it) => NodeOrToken::Node(it.to_owned()), | ||
325 | }); | 326 | }); |
326 | 327 | ||
327 | let before = old_children.by_ref().take(start).collect::<Vec<_>>(); | 328 | let before = old_children.by_ref().take(start).collect::<Vec<_>>(); |
@@ -487,9 +488,9 @@ impl<'a> SyntaxRewriter<'a> { | |||
487 | /// Returns `None` when there are no replacements. | 488 | /// Returns `None` when there are no replacements. |
488 | pub fn rewrite_root(&self) -> Option<SyntaxNode> { | 489 | pub fn rewrite_root(&self) -> Option<SyntaxNode> { |
489 | let _p = profile::span("rewrite_root"); | 490 | let _p = profile::span("rewrite_root"); |
490 | fn element_to_node_or_parent(element: &SyntaxElement) -> SyntaxNode { | 491 | fn element_to_node_or_parent(element: &SyntaxElement) -> Option<SyntaxNode> { |
491 | match element { | 492 | match element { |
492 | SyntaxElement::Node(it) => it.clone(), | 493 | SyntaxElement::Node(it) => Some(it.clone()), |
493 | SyntaxElement::Token(it) => it.parent(), | 494 | SyntaxElement::Token(it) => it.parent(), |
494 | } | 495 | } |
495 | } | 496 | } |
@@ -497,9 +498,9 @@ impl<'a> SyntaxRewriter<'a> { | |||
497 | assert!(self.f.is_none()); | 498 | assert!(self.f.is_none()); |
498 | self.replacements | 499 | self.replacements |
499 | .keys() | 500 | .keys() |
500 | .map(element_to_node_or_parent) | 501 | .filter_map(element_to_node_or_parent) |
501 | .chain(self.insertions.keys().map(|pos| match pos { | 502 | .chain(self.insertions.keys().filter_map(|pos| match pos { |
502 | InsertPos::FirstChildOf(it) => it.clone(), | 503 | InsertPos::FirstChildOf(it) => Some(it.clone()), |
503 | InsertPos::After(it) => element_to_node_or_parent(it), | 504 | InsertPos::After(it) => element_to_node_or_parent(it), |
504 | })) | 505 | })) |
505 | // If we only have one replacement/insertion, we must return its parent node, since `rewrite` does | 506 | // If we only have one replacement/insertion, we must return its parent node, since `rewrite` does |
@@ -552,7 +553,7 @@ impl<'a> SyntaxRewriter<'a> { | |||
552 | }; | 553 | }; |
553 | } else { | 554 | } else { |
554 | match element { | 555 | match element { |
555 | NodeOrToken::Token(it) => acc.push(NodeOrToken::Token(it.green().clone())), | 556 | NodeOrToken::Token(it) => acc.push(NodeOrToken::Token(it.green().to_owned())), |
556 | NodeOrToken::Node(it) => { | 557 | NodeOrToken::Node(it) => { |
557 | acc.push(NodeOrToken::Node(self.rewrite_children(it))); | 558 | acc.push(NodeOrToken::Node(self.rewrite_children(it))); |
558 | } | 559 | } |
@@ -567,7 +568,7 @@ impl<'a> SyntaxRewriter<'a> { | |||
567 | fn element_to_green(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> { | 568 | fn element_to_green(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> { |
568 | match element { | 569 | match element { |
569 | NodeOrToken::Node(it) => NodeOrToken::Node(it.green().to_owned()), | 570 | NodeOrToken::Node(it) => NodeOrToken::Node(it.green().to_owned()), |
570 | NodeOrToken::Token(it) => NodeOrToken::Token(it.green().clone()), | 571 | NodeOrToken::Token(it) => NodeOrToken::Token(it.green().to_owned()), |
571 | } | 572 | } |
572 | } | 573 | } |
573 | 574 | ||
@@ -625,7 +626,7 @@ fn position_of_child(parent: &SyntaxNode, child: SyntaxElement) -> usize { | |||
625 | fn to_green_element(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> { | 626 | fn to_green_element(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> { |
626 | match element { | 627 | match element { |
627 | NodeOrToken::Node(it) => it.green().to_owned().into(), | 628 | NodeOrToken::Node(it) => it.green().to_owned().into(), |
628 | NodeOrToken::Token(it) => it.green().clone().into(), | 629 | NodeOrToken::Token(it) => it.green().to_owned().into(), |
629 | } | 630 | } |
630 | } | 631 | } |
631 | 632 | ||
diff --git a/crates/syntax/src/ast.rs b/crates/syntax/src/ast.rs index b3a24d39d..19261686c 100644 --- a/crates/syntax/src/ast.rs +++ b/crates/syntax/src/ast.rs | |||
@@ -6,6 +6,7 @@ mod token_ext; | |||
6 | mod node_ext; | 6 | mod node_ext; |
7 | mod expr_ext; | 7 | mod expr_ext; |
8 | pub mod edit; | 8 | pub mod edit; |
9 | pub mod edit_in_place; | ||
9 | pub mod make; | 10 | pub mod make; |
10 | 11 | ||
11 | use std::marker::PhantomData; | 12 | use std::marker::PhantomData; |
@@ -40,6 +41,12 @@ pub trait AstNode { | |||
40 | Self: Sized; | 41 | Self: Sized; |
41 | 42 | ||
42 | fn syntax(&self) -> &SyntaxNode; | 43 | fn syntax(&self) -> &SyntaxNode; |
44 | fn clone_for_update(&self) -> Self | ||
45 | where | ||
46 | Self: Sized, | ||
47 | { | ||
48 | Self::cast(self.syntax().clone_for_update()).unwrap() | ||
49 | } | ||
43 | } | 50 | } |
44 | 51 | ||
45 | /// Like `AstNode`, but wraps tokens rather than interior nodes. | 52 | /// Like `AstNode`, but wraps tokens rather than interior nodes. |
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs new file mode 100644 index 000000000..449b058fb --- /dev/null +++ b/crates/syntax/src/ast/edit_in_place.rs | |||
@@ -0,0 +1,129 @@ | |||
1 | //! Structural editing for ast. | ||
2 | |||
3 | use std::iter::empty; | ||
4 | |||
5 | use ast::{edit::AstNodeEdit, make, GenericParamsOwner, WhereClause}; | ||
6 | use parser::T; | ||
7 | |||
8 | use crate::{ | ||
9 | ast, | ||
10 | ted::{self, Position}, | ||
11 | AstNode, Direction, SyntaxElement, | ||
12 | }; | ||
13 | |||
14 | use super::NameOwner; | ||
15 | |||
16 | pub trait GenericParamsOwnerEdit: ast::GenericParamsOwner + AstNodeEdit { | ||
17 | fn get_or_create_where_clause(&self) -> ast::WhereClause; | ||
18 | } | ||
19 | |||
20 | impl GenericParamsOwnerEdit for ast::Fn { | ||
21 | fn get_or_create_where_clause(&self) -> WhereClause { | ||
22 | if self.where_clause().is_none() { | ||
23 | let position = if let Some(ty) = self.ret_type() { | ||
24 | Position::after(ty.syntax().clone()) | ||
25 | } else if let Some(param_list) = self.param_list() { | ||
26 | Position::after(param_list.syntax().clone()) | ||
27 | } else { | ||
28 | Position::last_child_of(self.syntax().clone()) | ||
29 | }; | ||
30 | create_where_clause(position) | ||
31 | } | ||
32 | self.where_clause().unwrap() | ||
33 | } | ||
34 | } | ||
35 | |||
36 | impl GenericParamsOwnerEdit for ast::Impl { | ||
37 | fn get_or_create_where_clause(&self) -> WhereClause { | ||
38 | if self.where_clause().is_none() { | ||
39 | let position = if let Some(items) = self.assoc_item_list() { | ||
40 | Position::before(items.syntax().clone()) | ||
41 | } else { | ||
42 | Position::last_child_of(self.syntax().clone()) | ||
43 | }; | ||
44 | create_where_clause(position) | ||
45 | } | ||
46 | self.where_clause().unwrap() | ||
47 | } | ||
48 | } | ||
49 | |||
50 | impl GenericParamsOwnerEdit for ast::Trait { | ||
51 | fn get_or_create_where_clause(&self) -> WhereClause { | ||
52 | if self.where_clause().is_none() { | ||
53 | let position = if let Some(items) = self.assoc_item_list() { | ||
54 | Position::before(items.syntax().clone()) | ||
55 | } else { | ||
56 | Position::last_child_of(self.syntax().clone()) | ||
57 | }; | ||
58 | create_where_clause(position) | ||
59 | } | ||
60 | self.where_clause().unwrap() | ||
61 | } | ||
62 | } | ||
63 | |||
64 | impl GenericParamsOwnerEdit for ast::Struct { | ||
65 | fn get_or_create_where_clause(&self) -> WhereClause { | ||
66 | if self.where_clause().is_none() { | ||
67 | let tfl = self.field_list().and_then(|fl| match fl { | ||
68 | ast::FieldList::RecordFieldList(_) => None, | ||
69 | ast::FieldList::TupleFieldList(it) => Some(it), | ||
70 | }); | ||
71 | let position = if let Some(tfl) = tfl { | ||
72 | Position::after(tfl.syntax().clone()) | ||
73 | } else if let Some(gpl) = self.generic_param_list() { | ||
74 | Position::after(gpl.syntax().clone()) | ||
75 | } else if let Some(name) = self.name() { | ||
76 | Position::after(name.syntax().clone()) | ||
77 | } else { | ||
78 | Position::last_child_of(self.syntax().clone()) | ||
79 | }; | ||
80 | create_where_clause(position) | ||
81 | } | ||
82 | self.where_clause().unwrap() | ||
83 | } | ||
84 | } | ||
85 | |||
86 | impl GenericParamsOwnerEdit for ast::Enum { | ||
87 | fn get_or_create_where_clause(&self) -> WhereClause { | ||
88 | if self.where_clause().is_none() { | ||
89 | let position = if let Some(gpl) = self.generic_param_list() { | ||
90 | Position::after(gpl.syntax().clone()) | ||
91 | } else if let Some(name) = self.name() { | ||
92 | Position::after(name.syntax().clone()) | ||
93 | } else { | ||
94 | Position::last_child_of(self.syntax().clone()) | ||
95 | }; | ||
96 | create_where_clause(position) | ||
97 | } | ||
98 | self.where_clause().unwrap() | ||
99 | } | ||
100 | } | ||
101 | |||
102 | fn create_where_clause(position: Position) { | ||
103 | let where_clause: SyntaxElement = | ||
104 | make::where_clause(empty()).clone_for_update().syntax().clone().into(); | ||
105 | ted::insert(position, where_clause); | ||
106 | } | ||
107 | |||
108 | impl ast::WhereClause { | ||
109 | pub fn add_predicate(&self, predicate: ast::WherePred) { | ||
110 | if let Some(pred) = self.predicates().last() { | ||
111 | if !pred.syntax().siblings_with_tokens(Direction::Next).any(|it| it.kind() == T![,]) { | ||
112 | ted::append_child_raw(self.syntax().clone(), make::token(T![,])); | ||
113 | } | ||
114 | } | ||
115 | ted::append_child(self.syntax().clone(), predicate.syntax().clone()) | ||
116 | } | ||
117 | } | ||
118 | |||
119 | impl ast::TypeBoundList { | ||
120 | pub fn remove(&self) { | ||
121 | if let Some(colon) = | ||
122 | self.syntax().siblings_with_tokens(Direction::Prev).find(|it| it.kind() == T![:]) | ||
123 | { | ||
124 | ted::remove_all(colon..=self.syntax().clone().into()) | ||
125 | } else { | ||
126 | ted::remove(self.syntax().clone()) | ||
127 | } | ||
128 | } | ||
129 | } | ||
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index 064931aec..6097178b6 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs | |||
@@ -1336,6 +1336,7 @@ pub enum Expr { | |||
1336 | Literal(Literal), | 1336 | Literal(Literal), |
1337 | LoopExpr(LoopExpr), | 1337 | LoopExpr(LoopExpr), |
1338 | MacroCall(MacroCall), | 1338 | MacroCall(MacroCall), |
1339 | MacroStmts(MacroStmts), | ||
1339 | MatchExpr(MatchExpr), | 1340 | MatchExpr(MatchExpr), |
1340 | MethodCallExpr(MethodCallExpr), | 1341 | MethodCallExpr(MethodCallExpr), |
1341 | ParenExpr(ParenExpr), | 1342 | ParenExpr(ParenExpr), |
@@ -3034,6 +3035,9 @@ impl From<LoopExpr> for Expr { | |||
3034 | impl From<MacroCall> for Expr { | 3035 | impl From<MacroCall> for Expr { |
3035 | fn from(node: MacroCall) -> Expr { Expr::MacroCall(node) } | 3036 | fn from(node: MacroCall) -> Expr { Expr::MacroCall(node) } |
3036 | } | 3037 | } |
3038 | impl From<MacroStmts> for Expr { | ||
3039 | fn from(node: MacroStmts) -> Expr { Expr::MacroStmts(node) } | ||
3040 | } | ||
3037 | impl From<MatchExpr> for Expr { | 3041 | impl From<MatchExpr> for Expr { |
3038 | fn from(node: MatchExpr) -> Expr { Expr::MatchExpr(node) } | 3042 | fn from(node: MatchExpr) -> Expr { Expr::MatchExpr(node) } |
3039 | } | 3043 | } |
@@ -3078,8 +3082,8 @@ impl AstNode for Expr { | |||
3078 | match kind { | 3082 | match kind { |
3079 | ARRAY_EXPR | AWAIT_EXPR | BIN_EXPR | BLOCK_EXPR | BOX_EXPR | BREAK_EXPR | CALL_EXPR | 3083 | ARRAY_EXPR | AWAIT_EXPR | BIN_EXPR | BLOCK_EXPR | BOX_EXPR | BREAK_EXPR | CALL_EXPR |
3080 | | CAST_EXPR | CLOSURE_EXPR | CONTINUE_EXPR | EFFECT_EXPR | FIELD_EXPR | FOR_EXPR | 3084 | | CAST_EXPR | CLOSURE_EXPR | CONTINUE_EXPR | EFFECT_EXPR | FIELD_EXPR | FOR_EXPR |
3081 | | IF_EXPR | INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_CALL | MATCH_EXPR | 3085 | | IF_EXPR | INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_CALL | MACRO_STMTS |
3082 | | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR | 3086 | | MATCH_EXPR | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR |
3083 | | RECORD_EXPR | REF_EXPR | RETURN_EXPR | TRY_EXPR | TUPLE_EXPR | WHILE_EXPR | 3087 | | RECORD_EXPR | REF_EXPR | RETURN_EXPR | TRY_EXPR | TUPLE_EXPR | WHILE_EXPR |
3084 | | YIELD_EXPR => true, | 3088 | | YIELD_EXPR => true, |
3085 | _ => false, | 3089 | _ => false, |
@@ -3105,6 +3109,7 @@ impl AstNode for Expr { | |||
3105 | LITERAL => Expr::Literal(Literal { syntax }), | 3109 | LITERAL => Expr::Literal(Literal { syntax }), |
3106 | LOOP_EXPR => Expr::LoopExpr(LoopExpr { syntax }), | 3110 | LOOP_EXPR => Expr::LoopExpr(LoopExpr { syntax }), |
3107 | MACRO_CALL => Expr::MacroCall(MacroCall { syntax }), | 3111 | MACRO_CALL => Expr::MacroCall(MacroCall { syntax }), |
3112 | MACRO_STMTS => Expr::MacroStmts(MacroStmts { syntax }), | ||
3108 | MATCH_EXPR => Expr::MatchExpr(MatchExpr { syntax }), | 3113 | MATCH_EXPR => Expr::MatchExpr(MatchExpr { syntax }), |
3109 | METHOD_CALL_EXPR => Expr::MethodCallExpr(MethodCallExpr { syntax }), | 3114 | METHOD_CALL_EXPR => Expr::MethodCallExpr(MethodCallExpr { syntax }), |
3110 | PAREN_EXPR => Expr::ParenExpr(ParenExpr { syntax }), | 3115 | PAREN_EXPR => Expr::ParenExpr(ParenExpr { syntax }), |
@@ -3142,6 +3147,7 @@ impl AstNode for Expr { | |||
3142 | Expr::Literal(it) => &it.syntax, | 3147 | Expr::Literal(it) => &it.syntax, |
3143 | Expr::LoopExpr(it) => &it.syntax, | 3148 | Expr::LoopExpr(it) => &it.syntax, |
3144 | Expr::MacroCall(it) => &it.syntax, | 3149 | Expr::MacroCall(it) => &it.syntax, |
3150 | Expr::MacroStmts(it) => &it.syntax, | ||
3145 | Expr::MatchExpr(it) => &it.syntax, | 3151 | Expr::MatchExpr(it) => &it.syntax, |
3146 | Expr::MethodCallExpr(it) => &it.syntax, | 3152 | Expr::MethodCallExpr(it) => &it.syntax, |
3147 | Expr::ParenExpr(it) => &it.syntax, | 3153 | Expr::ParenExpr(it) => &it.syntax, |
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 05a6b0b25..810c8d4c8 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs | |||
@@ -174,6 +174,11 @@ pub fn block_expr( | |||
174 | pub fn expr_unit() -> ast::Expr { | 174 | pub fn expr_unit() -> ast::Expr { |
175 | expr_from_text("()") | 175 | expr_from_text("()") |
176 | } | 176 | } |
177 | pub fn expr_literal(text: &str) -> ast::Literal { | ||
178 | assert_eq!(text.trim(), text); | ||
179 | ast_from_text(&format!("fn f() {{ let _ = {}; }}", text)) | ||
180 | } | ||
181 | |||
177 | pub fn expr_empty_block() -> ast::Expr { | 182 | pub fn expr_empty_block() -> ast::Expr { |
178 | expr_from_text("{}") | 183 | expr_from_text("{}") |
179 | } | 184 | } |
@@ -390,6 +395,7 @@ pub fn token(kind: SyntaxKind) -> SyntaxToken { | |||
390 | tokens::SOURCE_FILE | 395 | tokens::SOURCE_FILE |
391 | .tree() | 396 | .tree() |
392 | .syntax() | 397 | .syntax() |
398 | .clone_for_update() | ||
393 | .descendants_with_tokens() | 399 | .descendants_with_tokens() |
394 | .filter_map(|it| it.into_token()) | 400 | .filter_map(|it| it.into_token()) |
395 | .find(|it| it.kind() == kind) | 401 | .find(|it| it.kind() == kind) |
@@ -544,6 +550,7 @@ pub mod tokens { | |||
544 | SOURCE_FILE | 550 | SOURCE_FILE |
545 | .tree() | 551 | .tree() |
546 | .syntax() | 552 | .syntax() |
553 | .clone_for_update() | ||
547 | .descendants_with_tokens() | 554 | .descendants_with_tokens() |
548 | .filter_map(|it| it.into_token()) | 555 | .filter_map(|it| it.into_token()) |
549 | .find(|it| it.kind() == WHITESPACE && it.text() == " ") | 556 | .find(|it| it.kind() == WHITESPACE && it.text() == " ") |
@@ -569,13 +576,16 @@ pub mod tokens { | |||
569 | } | 576 | } |
570 | 577 | ||
571 | pub fn single_newline() -> SyntaxToken { | 578 | pub fn single_newline() -> SyntaxToken { |
572 | SOURCE_FILE | 579 | let res = SOURCE_FILE |
573 | .tree() | 580 | .tree() |
574 | .syntax() | 581 | .syntax() |
582 | .clone_for_update() | ||
575 | .descendants_with_tokens() | 583 | .descendants_with_tokens() |
576 | .filter_map(|it| it.into_token()) | 584 | .filter_map(|it| it.into_token()) |
577 | .find(|it| it.kind() == WHITESPACE && it.text() == "\n") | 585 | .find(|it| it.kind() == WHITESPACE && it.text() == "\n") |
578 | .unwrap() | 586 | .unwrap(); |
587 | res.detach(); | ||
588 | res | ||
579 | } | 589 | } |
580 | 590 | ||
581 | pub fn blank_line() -> SyntaxToken { | 591 | pub fn blank_line() -> SyntaxToken { |
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index 52ac97c84..0b0d39a75 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs | |||
@@ -34,7 +34,9 @@ impl ast::NameRef { | |||
34 | } | 34 | } |
35 | 35 | ||
36 | fn text_of_first_token(node: &SyntaxNode) -> &str { | 36 | fn text_of_first_token(node: &SyntaxNode) -> &str { |
37 | node.green().children().next().and_then(|it| it.into_token()).unwrap().text() | 37 | let t = |
38 | node.green().children().next().and_then(|it| it.into_token()).unwrap().text().to_string(); | ||
39 | Box::leak(Box::new(t)) | ||
38 | } | 40 | } |
39 | 41 | ||
40 | pub enum Macro { | 42 | pub enum Macro { |
diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index 09e212e8c..2a5c61171 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs | |||
@@ -38,6 +38,7 @@ pub mod ast; | |||
38 | #[doc(hidden)] | 38 | #[doc(hidden)] |
39 | pub mod fuzz; | 39 | pub mod fuzz; |
40 | pub mod utils; | 40 | pub mod utils; |
41 | pub mod ted; | ||
41 | 42 | ||
42 | use std::{marker::PhantomData, sync::Arc}; | 43 | use std::{marker::PhantomData, sync::Arc}; |
43 | 44 | ||
diff --git a/crates/syntax/src/parsing/reparsing.rs b/crates/syntax/src/parsing/reparsing.rs index 3d637bf91..4ad50ab72 100644 --- a/crates/syntax/src/parsing/reparsing.rs +++ b/crates/syntax/src/parsing/reparsing.rs | |||
@@ -124,11 +124,7 @@ fn is_contextual_kw(text: &str) -> bool { | |||
124 | fn find_reparsable_node(node: &SyntaxNode, range: TextRange) -> Option<(SyntaxNode, Reparser)> { | 124 | fn find_reparsable_node(node: &SyntaxNode, range: TextRange) -> Option<(SyntaxNode, Reparser)> { |
125 | let node = node.covering_element(range); | 125 | let node = node.covering_element(range); |
126 | 126 | ||
127 | let mut ancestors = match node { | 127 | node.ancestors().find_map(|node| { |
128 | NodeOrToken::Token(it) => it.parent().ancestors(), | ||
129 | NodeOrToken::Node(it) => it.ancestors(), | ||
130 | }; | ||
131 | ancestors.find_map(|node| { | ||
132 | let first_child = node.first_child_or_token().map(|it| it.kind()); | 128 | let first_child = node.first_child_or_token().map(|it| it.kind()); |
133 | let parent = node.parent().map(|it| it.kind()); | 129 | let parent = node.parent().map(|it| it.kind()); |
134 | Reparser::for_node(node.kind(), first_child, parent).map(|r| (node, r)) | 130 | Reparser::for_node(node.kind(), first_child, parent).map(|r| (node, r)) |
diff --git a/crates/syntax/src/ted.rs b/crates/syntax/src/ted.rs new file mode 100644 index 000000000..76f950ef9 --- /dev/null +++ b/crates/syntax/src/ted.rs | |||
@@ -0,0 +1,126 @@ | |||
1 | //! Primitive tree editor, ed for trees. | ||
2 | //! | ||
3 | //! The `_raw`-suffixed functions insert elements as is, unsuffixed versions fix | ||
4 | //! up elements around the edges. | ||
5 | use std::ops::RangeInclusive; | ||
6 | |||
7 | use parser::T; | ||
8 | |||
9 | use crate::{ast::make, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken}; | ||
10 | |||
11 | #[derive(Debug)] | ||
12 | pub struct Position { | ||
13 | repr: PositionRepr, | ||
14 | } | ||
15 | |||
16 | #[derive(Debug)] | ||
17 | enum PositionRepr { | ||
18 | FirstChild(SyntaxNode), | ||
19 | After(SyntaxElement), | ||
20 | } | ||
21 | |||
22 | impl Position { | ||
23 | pub fn after(elem: impl Into<SyntaxElement>) -> Position { | ||
24 | let repr = PositionRepr::After(elem.into()); | ||
25 | Position { repr } | ||
26 | } | ||
27 | pub fn before(elem: impl Into<SyntaxElement>) -> Position { | ||
28 | let elem = elem.into(); | ||
29 | let repr = match elem.prev_sibling_or_token() { | ||
30 | Some(it) => PositionRepr::After(it), | ||
31 | None => PositionRepr::FirstChild(elem.parent().unwrap()), | ||
32 | }; | ||
33 | Position { repr } | ||
34 | } | ||
35 | pub fn first_child_of(node: impl Into<SyntaxNode>) -> Position { | ||
36 | let repr = PositionRepr::FirstChild(node.into()); | ||
37 | Position { repr } | ||
38 | } | ||
39 | pub fn last_child_of(node: impl Into<SyntaxNode>) -> Position { | ||
40 | let node = node.into(); | ||
41 | let repr = match node.last_child_or_token() { | ||
42 | Some(it) => PositionRepr::After(it), | ||
43 | None => PositionRepr::FirstChild(node), | ||
44 | }; | ||
45 | Position { repr } | ||
46 | } | ||
47 | } | ||
48 | |||
49 | pub fn insert(position: Position, elem: impl Into<SyntaxElement>) { | ||
50 | insert_all(position, vec![elem.into()]) | ||
51 | } | ||
52 | pub fn insert_raw(position: Position, elem: impl Into<SyntaxElement>) { | ||
53 | insert_all_raw(position, vec![elem.into()]) | ||
54 | } | ||
55 | pub fn insert_all(position: Position, mut elements: Vec<SyntaxElement>) { | ||
56 | if let Some(first) = elements.first() { | ||
57 | if let Some(ws) = ws_before(&position, first) { | ||
58 | elements.insert(0, ws.into()) | ||
59 | } | ||
60 | } | ||
61 | if let Some(last) = elements.last() { | ||
62 | if let Some(ws) = ws_after(&position, last) { | ||
63 | elements.push(ws.into()) | ||
64 | } | ||
65 | } | ||
66 | insert_all_raw(position, elements) | ||
67 | } | ||
68 | pub fn insert_all_raw(position: Position, elements: Vec<SyntaxElement>) { | ||
69 | let (parent, index) = match position.repr { | ||
70 | PositionRepr::FirstChild(parent) => (parent, 0), | ||
71 | PositionRepr::After(child) => (child.parent().unwrap(), child.index() + 1), | ||
72 | }; | ||
73 | parent.splice_children(index..index, elements); | ||
74 | } | ||
75 | |||
76 | pub fn remove(elem: impl Into<SyntaxElement>) { | ||
77 | let elem = elem.into(); | ||
78 | remove_all(elem.clone()..=elem) | ||
79 | } | ||
80 | pub fn remove_all(range: RangeInclusive<SyntaxElement>) { | ||
81 | replace_all(range, Vec::new()) | ||
82 | } | ||
83 | |||
84 | pub fn replace(old: impl Into<SyntaxElement>, new: impl Into<SyntaxElement>) { | ||
85 | let old = old.into(); | ||
86 | replace_all(old.clone()..=old, vec![new.into()]) | ||
87 | } | ||
88 | pub fn replace_all(range: RangeInclusive<SyntaxElement>, new: Vec<SyntaxElement>) { | ||
89 | let start = range.start().index(); | ||
90 | let end = range.end().index(); | ||
91 | let parent = range.start().parent().unwrap(); | ||
92 | parent.splice_children(start..end + 1, new) | ||
93 | } | ||
94 | |||
95 | pub fn append_child(node: impl Into<SyntaxNode>, child: impl Into<SyntaxElement>) { | ||
96 | let position = Position::last_child_of(node); | ||
97 | insert(position, child) | ||
98 | } | ||
99 | pub fn append_child_raw(node: impl Into<SyntaxNode>, child: impl Into<SyntaxElement>) { | ||
100 | let position = Position::last_child_of(node); | ||
101 | insert_raw(position, child) | ||
102 | } | ||
103 | |||
104 | fn ws_before(position: &Position, new: &SyntaxElement) -> Option<SyntaxToken> { | ||
105 | let prev = match &position.repr { | ||
106 | PositionRepr::FirstChild(_) => return None, | ||
107 | PositionRepr::After(it) => it, | ||
108 | }; | ||
109 | ws_between(prev, new) | ||
110 | } | ||
111 | fn ws_after(position: &Position, new: &SyntaxElement) -> Option<SyntaxToken> { | ||
112 | let next = match &position.repr { | ||
113 | PositionRepr::FirstChild(parent) => parent.first_child_or_token()?, | ||
114 | PositionRepr::After(sibling) => sibling.next_sibling_or_token()?, | ||
115 | }; | ||
116 | ws_between(new, &next) | ||
117 | } | ||
118 | fn ws_between(left: &SyntaxElement, right: &SyntaxElement) -> Option<SyntaxToken> { | ||
119 | if left.kind() == SyntaxKind::WHITESPACE || right.kind() == SyntaxKind::WHITESPACE { | ||
120 | return None; | ||
121 | } | ||
122 | if right.kind() == T![;] || right.kind() == T![,] { | ||
123 | return None; | ||
124 | } | ||
125 | Some(make::tokens::single_space().into()) | ||
126 | } | ||