From 1859df37fd6e308ea4304f69baae038ec09fe424 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 16 May 2021 18:10:56 +0300 Subject: internal: use mutable syntax trees when filling fields --- crates/ide/src/diagnostics.rs | 6 +- crates/ide/src/diagnostics/fixes.rs | 7 ++- crates/syntax/src/ast/edit.rs | 100 +-------------------------------- crates/syntax/src/ast/edit_in_place.rs | 40 +++++++++++++ 4 files changed, 49 insertions(+), 104 deletions(-) diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 273d8cfbb..d5fba6740 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs @@ -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() {} diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs index 15821500f..695b59e27 100644 --- a/crates/ide/src/diagnostics/fixes.rs +++ b/crates/ide/src/diagnostics/fixes.rs @@ -100,11 +100,12 @@ impl DiagnosticWithFix for MissingFields { 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 = { 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; 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 @@ impl 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 = 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 @@ impl IndentLevel { } } -// FIXME: replace usages with IndentLevel above -fn leading_indent(node: &SyntaxNode) -> Option { - 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 { iter::successors(Some(token), |token| token.prev_token()) } 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 { } } +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() -- cgit v1.2.3