diff options
Diffstat (limited to 'crates/syntax')
-rw-r--r-- | crates/syntax/src/ast/edit.rs | 100 | ||||
-rw-r--r-- | crates/syntax/src/ast/edit_in_place.rs | 40 |
2 files changed, 42 insertions, 98 deletions
diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs index 5e6c1d44e..61952377f 100644 --- a/crates/syntax/src/ast/edit.rs +++ b/crates/syntax/src/ast/edit.rs | |||
@@ -10,12 +10,8 @@ use arrayvec::ArrayVec; | |||
10 | 10 | ||
11 | use crate::{ | 11 | use crate::{ |
12 | algo, | 12 | algo, |
13 | ast::{ | 13 | ast::{self, make, AstNode}, |
14 | self, | 14 | ted, AstToken, InsertPosition, NodeOrToken, SyntaxElement, SyntaxKind, |
15 | make::{self, tokens}, | ||
16 | AstNode, | ||
17 | }, | ||
18 | ted, AstToken, Direction, InsertPosition, NodeOrToken, SmolStr, SyntaxElement, SyntaxKind, | ||
19 | SyntaxKind::{ATTR, COMMENT, WHITESPACE}, | 15 | SyntaxKind::{ATTR, COMMENT, WHITESPACE}, |
20 | SyntaxNode, SyntaxToken, T, | 16 | SyntaxNode, SyntaxToken, T, |
21 | }; | 17 | }; |
@@ -29,82 +25,6 @@ impl ast::BinExpr { | |||
29 | } | 25 | } |
30 | } | 26 | } |
31 | 27 | ||
32 | impl ast::RecordExprFieldList { | ||
33 | #[must_use] | ||
34 | pub fn append_field(&self, field: &ast::RecordExprField) -> ast::RecordExprFieldList { | ||
35 | self.insert_field(InsertPosition::Last, field) | ||
36 | } | ||
37 | |||
38 | #[must_use] | ||
39 | pub fn insert_field( | ||
40 | &self, | ||
41 | position: InsertPosition<&'_ ast::RecordExprField>, | ||
42 | field: &ast::RecordExprField, | ||
43 | ) -> ast::RecordExprFieldList { | ||
44 | let is_multiline = self.syntax().text().contains_char('\n'); | ||
45 | let ws; | ||
46 | let space = if is_multiline { | ||
47 | ws = tokens::WsBuilder::new(&format!( | ||
48 | "\n{} ", | ||
49 | leading_indent(self.syntax()).unwrap_or_default() | ||
50 | )); | ||
51 | ws.ws() | ||
52 | } else { | ||
53 | tokens::single_space() | ||
54 | }; | ||
55 | |||
56 | let mut to_insert: ArrayVec<SyntaxElement, 4> = ArrayVec::new(); | ||
57 | to_insert.push(space.into()); | ||
58 | to_insert.push(field.syntax().clone().into()); | ||
59 | to_insert.push(make::token(T![,]).into()); | ||
60 | |||
61 | macro_rules! after_l_curly { | ||
62 | () => {{ | ||
63 | let anchor = match self.l_curly_token() { | ||
64 | Some(it) => it.into(), | ||
65 | None => return self.clone(), | ||
66 | }; | ||
67 | InsertPosition::After(anchor) | ||
68 | }}; | ||
69 | } | ||
70 | |||
71 | macro_rules! after_field { | ||
72 | ($anchor:expr) => { | ||
73 | if let Some(comma) = $anchor | ||
74 | .syntax() | ||
75 | .siblings_with_tokens(Direction::Next) | ||
76 | .find(|it| it.kind() == T![,]) | ||
77 | { | ||
78 | InsertPosition::After(comma) | ||
79 | } else { | ||
80 | to_insert.insert(0, make::token(T![,]).into()); | ||
81 | InsertPosition::After($anchor.syntax().clone().into()) | ||
82 | } | ||
83 | }; | ||
84 | } | ||
85 | |||
86 | let position = match position { | ||
87 | InsertPosition::First => after_l_curly!(), | ||
88 | InsertPosition::Last => { | ||
89 | if !is_multiline { | ||
90 | // don't insert comma before curly | ||
91 | to_insert.pop(); | ||
92 | } | ||
93 | match self.fields().last() { | ||
94 | Some(it) => after_field!(it), | ||
95 | None => after_l_curly!(), | ||
96 | } | ||
97 | } | ||
98 | InsertPosition::Before(anchor) => { | ||
99 | InsertPosition::Before(anchor.syntax().clone().into()) | ||
100 | } | ||
101 | InsertPosition::After(anchor) => after_field!(anchor), | ||
102 | }; | ||
103 | |||
104 | self.insert_children(position, to_insert) | ||
105 | } | ||
106 | } | ||
107 | |||
108 | impl ast::Path { | 28 | impl ast::Path { |
109 | #[must_use] | 29 | #[must_use] |
110 | pub fn with_segment(&self, segment: ast::PathSegment) -> ast::Path { | 30 | pub fn with_segment(&self, segment: ast::PathSegment) -> ast::Path { |
@@ -308,22 +228,6 @@ impl IndentLevel { | |||
308 | } | 228 | } |
309 | } | 229 | } |
310 | 230 | ||
311 | // FIXME: replace usages with IndentLevel above | ||
312 | fn leading_indent(node: &SyntaxNode) -> Option<SmolStr> { | ||
313 | for token in prev_tokens(node.first_token()?) { | ||
314 | if let Some(ws) = ast::Whitespace::cast(token.clone()) { | ||
315 | let ws_text = ws.text(); | ||
316 | if let Some(pos) = ws_text.rfind('\n') { | ||
317 | return Some(ws_text[pos + 1..].into()); | ||
318 | } | ||
319 | } | ||
320 | if token.text().contains('\n') { | ||
321 | break; | ||
322 | } | ||
323 | } | ||
324 | None | ||
325 | } | ||
326 | |||
327 | fn prev_tokens(token: SyntaxToken) -> impl Iterator<Item = SyntaxToken> { | 231 | fn prev_tokens(token: SyntaxToken) -> impl Iterator<Item = SyntaxToken> { |
328 | iter::successors(Some(token), |token| token.prev_token()) | 232 | iter::successors(Some(token), |token| token.prev_token()) |
329 | } | 233 | } |
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs index abab0269a..14624c682 100644 --- a/crates/syntax/src/ast/edit_in_place.rs +++ b/crates/syntax/src/ast/edit_in_place.rs | |||
@@ -368,6 +368,46 @@ impl ast::MatchArmList { | |||
368 | } | 368 | } |
369 | } | 369 | } |
370 | 370 | ||
371 | impl ast::RecordExprFieldList { | ||
372 | pub fn add_field(&self, field: ast::RecordExprField) { | ||
373 | let is_multiline = self.syntax().text().contains_char('\n'); | ||
374 | let whitespace = if is_multiline { | ||
375 | let indent = IndentLevel::from_node(self.syntax()) + 1; | ||
376 | make::tokens::whitespace(&format!("\n{}", indent)) | ||
377 | } else { | ||
378 | make::tokens::single_space() | ||
379 | }; | ||
380 | |||
381 | let position = match self.fields().last() { | ||
382 | Some(last_field) => { | ||
383 | let comma = match last_field | ||
384 | .syntax() | ||
385 | .siblings_with_tokens(Direction::Next) | ||
386 | .filter_map(|it| it.into_token()) | ||
387 | .find(|it| it.kind() == T![,]) | ||
388 | { | ||
389 | Some(it) => it, | ||
390 | None => { | ||
391 | let comma = ast::make::token(T![,]); | ||
392 | ted::insert(Position::after(last_field.syntax()), &comma); | ||
393 | comma | ||
394 | } | ||
395 | }; | ||
396 | Position::after(comma) | ||
397 | } | ||
398 | None => match self.l_curly_token() { | ||
399 | Some(it) => Position::after(it), | ||
400 | None => Position::last_child_of(self.syntax()), | ||
401 | }, | ||
402 | }; | ||
403 | |||
404 | ted::insert_all(position, vec![whitespace.into(), field.syntax().clone().into()]); | ||
405 | if is_multiline { | ||
406 | ted::insert(Position::after(field.syntax()), ast::make::token(T![,])); | ||
407 | } | ||
408 | } | ||
409 | } | ||
410 | |||
371 | fn normalize_ws_between_braces(node: &SyntaxNode) -> Option<()> { | 411 | fn normalize_ws_between_braces(node: &SyntaxNode) -> Option<()> { |
372 | let l = node | 412 | let l = node |
373 | .children_with_tokens() | 413 | .children_with_tokens() |