]> git.lizzy.rs Git - rust.git/commitdiff
internal: use mutable syntax trees when filling fields
authorAleksey Kladov <aleksey.kladov@gmail.com>
Sun, 16 May 2021 15:10:56 +0000 (18:10 +0300)
committerAleksey Kladov <aleksey.kladov@gmail.com>
Sun, 16 May 2021 15:10:56 +0000 (18:10 +0300)
crates/ide/src/diagnostics.rs
crates/ide/src/diagnostics/fixes.rs
crates/syntax/src/ast/edit.rs
crates/syntax/src/ast/edit_in_place.rs

index 273d8cfbb50f9308e1128ffdbd54873c4a7e02d2..d5fba6740fadc8d5166253fb0dbdf083d56643a9 100644 (file)
@@ -579,7 +579,7 @@ fn test_fn() {
 struct TestStruct { one: i32, two: i64 }
 
 fn test_fn() {
-    let s = TestStruct { one: (), two: ()};
+    let s = TestStruct { one: (), two: () };
 }
 "#,
         );
@@ -599,7 +599,7 @@ impl TestStruct {
 struct TestStruct { one: i32 }
 
 impl TestStruct {
-    fn test_fn() { let s = Self { one: ()}; }
+    fn test_fn() { let s = Self { one: () }; }
 }
 "#,
         );
@@ -792,7 +792,7 @@ fn main() {
 pub struct Foo { pub a: i32, pub b: i32 }
 "#,
             r#"
-fn some(, b: ()) {}
+fn some(, b: () ) {}
 fn items() {}
 fn here() {}
 
index 15821500f1acc765daddb7d5450335157617de59..695b59e27e6c7dce4deaf6222e1576335017844b 100644 (file)
@@ -100,11 +100,12 @@ fn fix(
         let root = sema.db.parse_or_expand(self.file)?;
         let field_list_parent = self.field_list_parent.to_node(&root);
         let old_field_list = field_list_parent.record_expr_field_list()?;
-        let mut new_field_list = old_field_list.clone();
+        let new_field_list = old_field_list.clone_for_update();
         for f in self.missed_fields.iter() {
             let field =
-                make::record_expr_field(make::name_ref(&f.to_string()), Some(make::expr_unit()));
-            new_field_list = new_field_list.append_field(&field);
+                make::record_expr_field(make::name_ref(&f.to_string()), Some(make::expr_unit()))
+                    .clone_for_update();
+            new_field_list.add_field(field);
         }
 
         let edit = {
index 5e6c1d44e8c7e9b969adae71340248050895d16c..61952377f63fae83bf5d09d1660d9290d1f268e7 100644 (file)
 
 use crate::{
     algo,
-    ast::{
-        self,
-        make::{self, tokens},
-        AstNode,
-    },
-    ted, AstToken, Direction, InsertPosition, NodeOrToken, SmolStr, SyntaxElement, SyntaxKind,
+    ast::{self, make, AstNode},
+    ted, AstToken, InsertPosition, NodeOrToken, SyntaxElement, SyntaxKind,
     SyntaxKind::{ATTR, COMMENT, WHITESPACE},
     SyntaxNode, SyntaxToken, T,
 };
@@ -29,82 +25,6 @@ pub fn replace_op(&self, op: SyntaxKind) -> Option<ast::BinExpr> {
     }
 }
 
-impl ast::RecordExprFieldList {
-    #[must_use]
-    pub fn append_field(&self, field: &ast::RecordExprField) -> ast::RecordExprFieldList {
-        self.insert_field(InsertPosition::Last, field)
-    }
-
-    #[must_use]
-    pub fn insert_field(
-        &self,
-        position: InsertPosition<&'_ ast::RecordExprField>,
-        field: &ast::RecordExprField,
-    ) -> ast::RecordExprFieldList {
-        let is_multiline = self.syntax().text().contains_char('\n');
-        let ws;
-        let space = if is_multiline {
-            ws = tokens::WsBuilder::new(&format!(
-                "\n{}    ",
-                leading_indent(self.syntax()).unwrap_or_default()
-            ));
-            ws.ws()
-        } else {
-            tokens::single_space()
-        };
-
-        let mut to_insert: ArrayVec<SyntaxElement, 4> = ArrayVec::new();
-        to_insert.push(space.into());
-        to_insert.push(field.syntax().clone().into());
-        to_insert.push(make::token(T![,]).into());
-
-        macro_rules! after_l_curly {
-            () => {{
-                let anchor = match self.l_curly_token() {
-                    Some(it) => it.into(),
-                    None => return self.clone(),
-                };
-                InsertPosition::After(anchor)
-            }};
-        }
-
-        macro_rules! after_field {
-            ($anchor:expr) => {
-                if let Some(comma) = $anchor
-                    .syntax()
-                    .siblings_with_tokens(Direction::Next)
-                    .find(|it| it.kind() == T![,])
-                {
-                    InsertPosition::After(comma)
-                } else {
-                    to_insert.insert(0, make::token(T![,]).into());
-                    InsertPosition::After($anchor.syntax().clone().into())
-                }
-            };
-        }
-
-        let position = match position {
-            InsertPosition::First => after_l_curly!(),
-            InsertPosition::Last => {
-                if !is_multiline {
-                    // don't insert comma before curly
-                    to_insert.pop();
-                }
-                match self.fields().last() {
-                    Some(it) => after_field!(it),
-                    None => after_l_curly!(),
-                }
-            }
-            InsertPosition::Before(anchor) => {
-                InsertPosition::Before(anchor.syntax().clone().into())
-            }
-            InsertPosition::After(anchor) => after_field!(anchor),
-        };
-
-        self.insert_children(position, to_insert)
-    }
-}
-
 impl ast::Path {
     #[must_use]
     pub fn with_segment(&self, segment: ast::PathSegment) -> ast::Path {
@@ -308,22 +228,6 @@ fn decrease_indent(self, node: SyntaxNode) -> SyntaxNode {
     }
 }
 
-// FIXME: replace usages with IndentLevel above
-fn leading_indent(node: &SyntaxNode) -> Option<SmolStr> {
-    for token in prev_tokens(node.first_token()?) {
-        if let Some(ws) = ast::Whitespace::cast(token.clone()) {
-            let ws_text = ws.text();
-            if let Some(pos) = ws_text.rfind('\n') {
-                return Some(ws_text[pos + 1..].into());
-            }
-        }
-        if token.text().contains('\n') {
-            break;
-        }
-    }
-    None
-}
-
 fn prev_tokens(token: SyntaxToken) -> impl Iterator<Item = SyntaxToken> {
     iter::successors(Some(token), |token| token.prev_token())
 }
index abab0269a027531f1dc58159b41c1c8cd08c6a7c..14624c68252c745b0d50a0e7f33970aa78f0e816 100644 (file)
@@ -368,6 +368,46 @@ pub fn add_arm(&self, arm: ast::MatchArm) {
     }
 }
 
+impl ast::RecordExprFieldList {
+    pub fn add_field(&self, field: ast::RecordExprField) {
+        let is_multiline = self.syntax().text().contains_char('\n');
+        let whitespace = if is_multiline {
+            let indent = IndentLevel::from_node(self.syntax()) + 1;
+            make::tokens::whitespace(&format!("\n{}", indent))
+        } else {
+            make::tokens::single_space()
+        };
+
+        let position = match self.fields().last() {
+            Some(last_field) => {
+                let comma = match last_field
+                    .syntax()
+                    .siblings_with_tokens(Direction::Next)
+                    .filter_map(|it| it.into_token())
+                    .find(|it| it.kind() == T![,])
+                {
+                    Some(it) => it,
+                    None => {
+                        let comma = ast::make::token(T![,]);
+                        ted::insert(Position::after(last_field.syntax()), &comma);
+                        comma
+                    }
+                };
+                Position::after(comma)
+            }
+            None => match self.l_curly_token() {
+                Some(it) => Position::after(it),
+                None => Position::last_child_of(self.syntax()),
+            },
+        };
+
+        ted::insert_all(position, vec![whitespace.into(), field.syntax().clone().into()]);
+        if is_multiline {
+            ted::insert(Position::after(field.syntax()), ast::make::token(T![,]));
+        }
+    }
+}
+
 fn normalize_ws_between_braces(node: &SyntaxNode) -> Option<()> {
     let l = node
         .children_with_tokens()