diff options
Diffstat (limited to 'crates/syntax/src/ast/edit_in_place.rs')
-rw-r--r-- | crates/syntax/src/ast/edit_in_place.rs | 88 |
1 files changed, 81 insertions, 7 deletions
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs index 168355555..ca777d057 100644 --- a/crates/syntax/src/ast/edit_in_place.rs +++ b/crates/syntax/src/ast/edit_in_place.rs | |||
@@ -2,11 +2,16 @@ | |||
2 | 2 | ||
3 | use std::iter::empty; | 3 | use std::iter::empty; |
4 | 4 | ||
5 | use parser::T; | 5 | use parser::{SyntaxKind, T}; |
6 | use rowan::SyntaxElement; | ||
6 | 7 | ||
7 | use crate::{ | 8 | use crate::{ |
8 | algo::neighbor, | 9 | algo::neighbor, |
9 | ast::{self, edit::AstNodeEdit, make, GenericParamsOwner, WhereClause}, | 10 | ast::{ |
11 | self, | ||
12 | edit::{AstNodeEdit, IndentLevel}, | ||
13 | make, GenericParamsOwner, | ||
14 | }, | ||
10 | ted::{self, Position}, | 15 | ted::{self, Position}, |
11 | AstNode, AstToken, Direction, | 16 | AstNode, AstToken, Direction, |
12 | }; | 17 | }; |
@@ -37,7 +42,7 @@ impl GenericParamsOwnerEdit for ast::Fn { | |||
37 | } | 42 | } |
38 | } | 43 | } |
39 | 44 | ||
40 | fn get_or_create_where_clause(&self) -> WhereClause { | 45 | fn get_or_create_where_clause(&self) -> ast::WhereClause { |
41 | if self.where_clause().is_none() { | 46 | if self.where_clause().is_none() { |
42 | let position = if let Some(ty) = self.ret_type() { | 47 | let position = if let Some(ty) = self.ret_type() { |
43 | Position::after(ty.syntax()) | 48 | Position::after(ty.syntax()) |
@@ -67,7 +72,7 @@ impl GenericParamsOwnerEdit for ast::Impl { | |||
67 | } | 72 | } |
68 | } | 73 | } |
69 | 74 | ||
70 | fn get_or_create_where_clause(&self) -> WhereClause { | 75 | fn get_or_create_where_clause(&self) -> ast::WhereClause { |
71 | if self.where_clause().is_none() { | 76 | if self.where_clause().is_none() { |
72 | let position = if let Some(items) = self.assoc_item_list() { | 77 | let position = if let Some(items) = self.assoc_item_list() { |
73 | Position::before(items.syntax()) | 78 | Position::before(items.syntax()) |
@@ -97,7 +102,7 @@ impl GenericParamsOwnerEdit for ast::Trait { | |||
97 | } | 102 | } |
98 | } | 103 | } |
99 | 104 | ||
100 | fn get_or_create_where_clause(&self) -> WhereClause { | 105 | fn get_or_create_where_clause(&self) -> ast::WhereClause { |
101 | if self.where_clause().is_none() { | 106 | if self.where_clause().is_none() { |
102 | let position = if let Some(items) = self.assoc_item_list() { | 107 | let position = if let Some(items) = self.assoc_item_list() { |
103 | Position::before(items.syntax()) | 108 | Position::before(items.syntax()) |
@@ -127,7 +132,7 @@ impl GenericParamsOwnerEdit for ast::Struct { | |||
127 | } | 132 | } |
128 | } | 133 | } |
129 | 134 | ||
130 | fn get_or_create_where_clause(&self) -> WhereClause { | 135 | fn get_or_create_where_clause(&self) -> ast::WhereClause { |
131 | if self.where_clause().is_none() { | 136 | if self.where_clause().is_none() { |
132 | let tfl = self.field_list().and_then(|fl| match fl { | 137 | let tfl = self.field_list().and_then(|fl| match fl { |
133 | ast::FieldList::RecordFieldList(_) => None, | 138 | ast::FieldList::RecordFieldList(_) => None, |
@@ -165,7 +170,7 @@ impl GenericParamsOwnerEdit for ast::Enum { | |||
165 | } | 170 | } |
166 | } | 171 | } |
167 | 172 | ||
168 | fn get_or_create_where_clause(&self) -> WhereClause { | 173 | fn get_or_create_where_clause(&self) -> ast::WhereClause { |
169 | if self.where_clause().is_none() { | 174 | if self.where_clause().is_none() { |
170 | let position = if let Some(gpl) = self.generic_param_list() { | 175 | let position = if let Some(gpl) = self.generic_param_list() { |
171 | Position::after(gpl.syntax()) | 176 | Position::after(gpl.syntax()) |
@@ -272,6 +277,75 @@ impl ast::Use { | |||
272 | } | 277 | } |
273 | } | 278 | } |
274 | 279 | ||
280 | impl ast::Impl { | ||
281 | pub fn get_or_create_assoc_item_list(&self) -> ast::AssocItemList { | ||
282 | if self.assoc_item_list().is_none() { | ||
283 | let assoc_item_list = make::assoc_item_list().clone_for_update(); | ||
284 | ted::append_child(self.syntax(), assoc_item_list.syntax()); | ||
285 | } | ||
286 | self.assoc_item_list().unwrap() | ||
287 | } | ||
288 | } | ||
289 | |||
290 | impl ast::AssocItemList { | ||
291 | pub fn add_item(&self, item: ast::AssocItem) { | ||
292 | let (indent, position, whitespace) = match self.assoc_items().last() { | ||
293 | Some(last_item) => ( | ||
294 | IndentLevel::from_node(last_item.syntax()), | ||
295 | Position::after(last_item.syntax()), | ||
296 | "\n\n", | ||
297 | ), | ||
298 | None => match self.l_curly_token() { | ||
299 | Some(l_curly) => { | ||
300 | self.normalize_ws_between_braces(); | ||
301 | (IndentLevel::from_token(&l_curly) + 1, Position::after(&l_curly), "\n") | ||
302 | } | ||
303 | None => (IndentLevel::single(), Position::last_child_of(self.syntax()), "\n"), | ||
304 | }, | ||
305 | }; | ||
306 | let elements: Vec<SyntaxElement<_>> = vec![ | ||
307 | make::tokens::whitespace(&format!("{}{}", whitespace, indent)).into(), | ||
308 | item.syntax().clone().into(), | ||
309 | ]; | ||
310 | ted::insert_all(position, elements); | ||
311 | } | ||
312 | |||
313 | fn normalize_ws_between_braces(&self) -> Option<()> { | ||
314 | let l = self.l_curly_token()?; | ||
315 | let r = self.r_curly_token()?; | ||
316 | let indent = IndentLevel::from_node(self.syntax()); | ||
317 | |||
318 | match l.next_sibling_or_token() { | ||
319 | Some(ws) if ws.kind() == SyntaxKind::WHITESPACE => { | ||
320 | if ws.next_sibling_or_token()?.into_token()? == r { | ||
321 | ted::replace(ws, make::tokens::whitespace(&format!("\n{}", indent))); | ||
322 | } | ||
323 | } | ||
324 | Some(ws) if ws.kind() == T!['}'] => { | ||
325 | ted::insert(Position::after(l), make::tokens::whitespace(&format!("\n{}", indent))); | ||
326 | } | ||
327 | _ => (), | ||
328 | } | ||
329 | Some(()) | ||
330 | } | ||
331 | } | ||
332 | |||
333 | impl ast::Fn { | ||
334 | pub fn get_or_create_body(&self) -> ast::BlockExpr { | ||
335 | if self.body().is_none() { | ||
336 | let body = make::ext::empty_block_expr().clone_for_update(); | ||
337 | match self.semicolon_token() { | ||
338 | Some(semi) => { | ||
339 | ted::replace(semi, body.syntax()); | ||
340 | ted::insert(Position::before(body.syntax), make::tokens::single_space()); | ||
341 | } | ||
342 | None => ted::append_child(self.syntax(), body.syntax()), | ||
343 | } | ||
344 | } | ||
345 | self.body().unwrap() | ||
346 | } | ||
347 | } | ||
348 | |||
275 | #[cfg(test)] | 349 | #[cfg(test)] |
276 | mod tests { | 350 | mod tests { |
277 | use std::fmt; | 351 | use std::fmt; |