diff options
Diffstat (limited to 'crates/syntax')
-rw-r--r-- | crates/syntax/src/ast/edit.rs | 2 | ||||
-rw-r--r-- | crates/syntax/src/ast/edit_in_place.rs | 52 | ||||
-rw-r--r-- | crates/syntax/src/ted.rs | 56 |
3 files changed, 91 insertions, 19 deletions
diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs index 0b3b76d4a..64fac13a7 100644 --- a/crates/syntax/src/ast/edit.rs +++ b/crates/syntax/src/ast/edit.rs | |||
@@ -479,7 +479,7 @@ impl ast::MatchArmList { | |||
479 | Some(t) => t, | 479 | Some(t) => t, |
480 | None => return self.clone(), | 480 | None => return self.clone(), |
481 | }; | 481 | }; |
482 | let position = InsertPosition::Before(r_curly.into()); | 482 | let position = InsertPosition::Before(r_curly); |
483 | let arm_ws = tokens::WsBuilder::new(" "); | 483 | let arm_ws = tokens::WsBuilder::new(" "); |
484 | let match_indent = &leading_indent(self.syntax()).unwrap_or_default(); | 484 | let match_indent = &leading_indent(self.syntax()).unwrap_or_default(); |
485 | let match_ws = tokens::WsBuilder::new(&format!("\n{}", match_indent)); | 485 | let match_ws = tokens::WsBuilder::new(&format!("\n{}", match_indent)); |
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs index 06cde591d..449b058fb 100644 --- a/crates/syntax/src/ast/edit_in_place.rs +++ b/crates/syntax/src/ast/edit_in_place.rs | |||
@@ -8,7 +8,7 @@ use parser::T; | |||
8 | use crate::{ | 8 | use crate::{ |
9 | ast, | 9 | ast, |
10 | ted::{self, Position}, | 10 | ted::{self, Position}, |
11 | AstNode, Direction, SyntaxKind, | 11 | AstNode, Direction, SyntaxElement, |
12 | }; | 12 | }; |
13 | 13 | ||
14 | use super::NameOwner; | 14 | use super::NameOwner; |
@@ -36,8 +36,8 @@ impl GenericParamsOwnerEdit for ast::Fn { | |||
36 | impl GenericParamsOwnerEdit for ast::Impl { | 36 | impl GenericParamsOwnerEdit for ast::Impl { |
37 | fn get_or_create_where_clause(&self) -> WhereClause { | 37 | fn get_or_create_where_clause(&self) -> WhereClause { |
38 | if self.where_clause().is_none() { | 38 | if self.where_clause().is_none() { |
39 | let position = if let Some(ty) = self.self_ty() { | 39 | let position = if let Some(items) = self.assoc_item_list() { |
40 | Position::after(ty.syntax().clone()) | 40 | Position::before(items.syntax().clone()) |
41 | } else { | 41 | } else { |
42 | Position::last_child_of(self.syntax().clone()) | 42 | Position::last_child_of(self.syntax().clone()) |
43 | }; | 43 | }; |
@@ -46,6 +46,21 @@ impl GenericParamsOwnerEdit for ast::Impl { | |||
46 | self.where_clause().unwrap() | 46 | self.where_clause().unwrap() |
47 | } | 47 | } |
48 | } | 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 | |||
49 | impl GenericParamsOwnerEdit for ast::Struct { | 64 | impl GenericParamsOwnerEdit for ast::Struct { |
50 | fn get_or_create_where_clause(&self) -> WhereClause { | 65 | fn get_or_create_where_clause(&self) -> WhereClause { |
51 | if self.where_clause().is_none() { | 66 | if self.where_clause().is_none() { |
@@ -68,26 +83,35 @@ impl GenericParamsOwnerEdit for ast::Struct { | |||
68 | } | 83 | } |
69 | } | 84 | } |
70 | 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 | |||
71 | fn create_where_clause(position: Position) { | 102 | fn create_where_clause(position: Position) { |
72 | let elements = vec![ | 103 | let where_clause: SyntaxElement = |
73 | make::tokens::single_space().into(), | 104 | make::where_clause(empty()).clone_for_update().syntax().clone().into(); |
74 | make::where_clause(empty()).clone_for_update().syntax().clone().into(), | 105 | ted::insert(position, where_clause); |
75 | ]; | ||
76 | ted::insert_all(position, elements); | ||
77 | } | 106 | } |
78 | 107 | ||
79 | impl ast::WhereClause { | 108 | impl ast::WhereClause { |
80 | pub fn add_predicate(&self, predicate: ast::WherePred) { | 109 | pub fn add_predicate(&self, predicate: ast::WherePred) { |
81 | if let Some(pred) = self.predicates().last() { | 110 | if let Some(pred) = self.predicates().last() { |
82 | if !pred.syntax().siblings_with_tokens(Direction::Next).any(|it| it.kind() == T![,]) { | 111 | if !pred.syntax().siblings_with_tokens(Direction::Next).any(|it| it.kind() == T![,]) { |
83 | ted::append_child(self.syntax().clone(), make::token(T![,])); | 112 | ted::append_child_raw(self.syntax().clone(), make::token(T![,])); |
84 | } | 113 | } |
85 | } | 114 | } |
86 | if self.syntax().children_with_tokens().last().map(|it| it.kind()) | ||
87 | != Some(SyntaxKind::WHITESPACE) | ||
88 | { | ||
89 | ted::append_child(self.syntax().clone(), make::tokens::single_space()); | ||
90 | } | ||
91 | ted::append_child(self.syntax().clone(), predicate.syntax().clone()) | 115 | ted::append_child(self.syntax().clone(), predicate.syntax().clone()) |
92 | } | 116 | } |
93 | } | 117 | } |
diff --git a/crates/syntax/src/ted.rs b/crates/syntax/src/ted.rs index 8d6175ed9..442dfa14a 100644 --- a/crates/syntax/src/ted.rs +++ b/crates/syntax/src/ted.rs | |||
@@ -1,8 +1,12 @@ | |||
1 | //! Primitive tree editor, ed for trees | 1 | //! Primitive tree editor, ed for trees. |
2 | #![allow(unused)] | 2 | //! |
3 | //! The `_raw`-suffixed functions insert elements as is, unsuffixed versions fix | ||
4 | //! up elements around the edges. | ||
3 | use std::ops::RangeInclusive; | 5 | use std::ops::RangeInclusive; |
4 | 6 | ||
5 | use crate::{SyntaxElement, SyntaxNode}; | 7 | use parser::T; |
8 | |||
9 | use crate::{ast::make, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken}; | ||
6 | 10 | ||
7 | #[derive(Debug)] | 11 | #[derive(Debug)] |
8 | pub struct Position { | 12 | pub struct Position { |
@@ -45,7 +49,23 @@ impl Position { | |||
45 | pub fn insert(position: Position, elem: impl Into<SyntaxElement>) { | 49 | pub fn insert(position: Position, elem: impl Into<SyntaxElement>) { |
46 | insert_all(position, vec![elem.into()]) | 50 | insert_all(position, vec![elem.into()]) |
47 | } | 51 | } |
48 | pub fn insert_all(position: Position, elements: Vec<SyntaxElement>) { | 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>) { | ||
49 | let (parent, index) = match position.repr { | 69 | let (parent, index) = match position.repr { |
50 | PositionRepr::FirstChild(parent) => (parent, 0), | 70 | PositionRepr::FirstChild(parent) => (parent, 0), |
51 | PositionRepr::After(child) => (child.parent().unwrap(), child.index() + 1), | 71 | PositionRepr::After(child) => (child.parent().unwrap(), child.index() + 1), |
@@ -76,3 +96,31 @@ pub fn append_child(node: impl Into<SyntaxNode>, child: impl Into<SyntaxElement> | |||
76 | let position = Position::last_child_of(node); | 96 | let position = Position::last_child_of(node); |
77 | insert(position, child) | 97 | insert(position, child) |
78 | } | 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()) | ||
126 | } | ||