Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/syntax/src/syntax_editor/edits.rs113
1 files changed, 108 insertions, 5 deletions
diff --git a/crates/syntax/src/syntax_editor/edits.rs b/crates/syntax/src/syntax_editor/edits.rs
index a684c0bfdb..0338d976b0 100644
--- a/crates/syntax/src/syntax_editor/edits.rs
+++ b/crates/syntax/src/syntax_editor/edits.rs
@@ -191,11 +191,7 @@ impl SyntaxEditor {
fn get_or_insert_comma_after(editor: &SyntaxEditor, syntax: &SyntaxNode) -> SyntaxToken {
let make = editor.make();
- match syntax
- .siblings_with_tokens(Direction::Next)
- .filter_map(|it| it.into_token())
- .find(|it| it.kind() == T![,])
- {
+ match comma_after(syntax) {
Some(it) => it,
None => {
let comma = make.token(T![,]);
@@ -241,6 +237,113 @@ impl ast::AssocItemList {
}
}
+impl ast::RecordExprFieldList {
+ pub fn add_fields(
+ &self,
+ editor: &SyntaxEditor,
+ fields: impl IntoIterator<Item = ast::RecordExprField>,
+ ) {
+ add_record_fields(
+ editor,
+ self.syntax(),
+ self.fields().last().map(|it| it.syntax().clone()),
+ self.l_curly_token(),
+ fields.into_iter().map(|it| it.syntax().clone().into()),
+ );
+ }
+}
+
+impl ast::RecordPatFieldList {
+ pub fn add_fields(
+ &self,
+ editor: &SyntaxEditor,
+ fields: impl IntoIterator<Item = ast::RecordPatField>,
+ ) {
+ add_record_fields(
+ editor,
+ self.syntax(),
+ self.fields().last().map(|it| it.syntax().clone()),
+ self.l_curly_token(),
+ fields.into_iter().map(|it| it.syntax().clone().into()),
+ );
+ }
+}
+
+fn add_record_fields(
+ editor: &SyntaxEditor,
+ field_list: &SyntaxNode,
+ last_field: Option<SyntaxNode>,
+ l_curly: Option<SyntaxToken>,
+ fields: impl Iterator<Item = SyntaxElement>,
+) {
+ let fields = fields.collect::<Vec<_>>();
+ if fields.is_empty() {
+ return;
+ }
+
+ let make = editor.make();
+ let is_multiline = field_list.text().contains_char('\n');
+ let whitespace = || {
+ if is_multiline {
+ let indent = IndentLevel::from_node(field_list) + 1;
+ make.whitespace(&format!("\n{indent}"))
+ } else {
+ make.whitespace(" ")
+ }
+ };
+
+ if is_multiline {
+ normalize_ws_between_braces(editor, field_list);
+ }
+
+ let mut elements = Vec::new();
+ let next_after_insert;
+ let position = match last_field {
+ Some(last_field) => match comma_after(&last_field) {
+ Some(comma) => {
+ next_after_insert = comma.next_sibling_or_token();
+ Position::after(comma)
+ }
+ None => {
+ next_after_insert = last_field.next_sibling_or_token();
+ elements.push(make.token(T![,]).into());
+ Position::after(last_field)
+ }
+ },
+ None => match l_curly {
+ Some(it) => {
+ next_after_insert = it.next_sibling_or_token();
+ Position::after(it)
+ }
+ None => {
+ next_after_insert = None;
+ Position::last_child_of(field_list)
+ }
+ },
+ };
+
+ let fields_len = fields.len();
+ for (idx, field) in fields.into_iter().enumerate() {
+ elements.push(whitespace().into());
+ elements.push(field);
+ if is_multiline || idx + 1 != fields_len {
+ elements.push(make.token(T![,]).into());
+ }
+ }
+ if !is_multiline && next_after_insert.is_some_and(|it| it.kind() != SyntaxKind::WHITESPACE) {
+ elements.push(make.whitespace(" ").into());
+ }
+
+ editor.insert_all(position, elements);
+}
+
+fn comma_after(syntax: &SyntaxNode) -> Option<SyntaxToken> {
+ syntax
+ .siblings_with_tokens(Direction::Next)
+ .filter_map(|it| it.into_token())
+ .find(|it| it.kind() == T![,])
+}
+
impl ast::Impl {
pub fn get_or_create_assoc_item_list_with_editor(
&self,