aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/ast/edit.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src/ast/edit.rs')
-rw-r--r--crates/ra_syntax/src/ast/edit.rs82
1 files changed, 81 insertions, 1 deletions
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs
index 2af6f573e..6e64c0675 100644
--- a/crates/ra_syntax/src/ast/edit.rs
+++ b/crates/ra_syntax/src/ast/edit.rs
@@ -12,7 +12,7 @@ use crate::{
12 make::{self, tokens}, 12 make::{self, tokens},
13 AstNode, 13 AstNode,
14 }, 14 },
15 AstToken, InsertPosition, SmolStr, SyntaxElement, 15 AstToken, Direction, InsertPosition, SmolStr, SyntaxElement,
16 SyntaxKind::{ATTR, COMMENT, WHITESPACE}, 16 SyntaxKind::{ATTR, COMMENT, WHITESPACE},
17 SyntaxNode, T, 17 SyntaxNode, T,
18}; 18};
@@ -105,6 +105,86 @@ impl ast::ItemList {
105 } 105 }
106} 106}
107 107
108impl ast::RecordFieldList {
109 #[must_use]
110 pub fn append_field(&self, field: &ast::RecordField) -> ast::RecordFieldList {
111 self.insert_field(InsertPosition::Last, field)
112 }
113
114 #[must_use]
115 pub fn insert_field(
116 &self,
117 position: InsertPosition<&'_ ast::RecordField>,
118 field: &ast::RecordField,
119 ) -> ast::RecordFieldList {
120 let is_multiline = self.syntax().text().contains_char('\n');
121 let ws;
122 let space = if is_multiline {
123 ws = tokens::WsBuilder::new(&format!(
124 "\n{} ",
125 leading_indent(self.syntax()).unwrap_or("".into())
126 ));
127 ws.ws()
128 } else {
129 tokens::single_space()
130 };
131
132 let mut to_insert: ArrayVec<[SyntaxElement; 4]> = ArrayVec::new();
133 to_insert.push(space.into());
134 to_insert.push(field.syntax().clone().into());
135 to_insert.push(tokens::comma().into());
136
137 macro_rules! after_l_curly {
138 () => {{
139 let anchor = match self.l_curly() {
140 Some(it) => it,
141 None => return self.clone(),
142 };
143 InsertPosition::After(anchor)
144 }};
145 }
146
147 macro_rules! after_field {
148 ($anchor:expr) => {
149 if let Some(comma) = $anchor
150 .syntax()
151 .siblings_with_tokens(Direction::Next)
152 .find(|it| it.kind() == T![,])
153 {
154 InsertPosition::After(comma)
155 } else {
156 to_insert.insert(0, tokens::comma().into());
157 InsertPosition::After($anchor.syntax().clone().into())
158 }
159 };
160 };
161
162 let position = match position {
163 InsertPosition::First => after_l_curly!(),
164 InsertPosition::Last => {
165 if !is_multiline {
166 // don't insert comma before curly
167 to_insert.pop();
168 }
169 match self.fields().last() {
170 Some(it) => after_field!(it),
171 None => after_l_curly!(),
172 }
173 }
174 InsertPosition::Before(anchor) => {
175 InsertPosition::Before(anchor.syntax().clone().into())
176 }
177 InsertPosition::After(anchor) => after_field!(anchor),
178 };
179
180 insert_children(self, position, to_insert.iter().cloned())
181 }
182
183 fn l_curly(&self) -> Option<SyntaxElement> {
184 self.syntax().children_with_tokens().find(|it| it.kind() == T!['{'])
185 }
186}
187
108pub fn strip_attrs_and_docs<N: ast::AttrsOwner>(node: N) -> N { 188pub fn strip_attrs_and_docs<N: ast::AttrsOwner>(node: N) -> N {
109 N::cast(strip_attrs_and_docs_inner(node.syntax().clone())).unwrap() 189 N::cast(strip_attrs_and_docs_inner(node.syntax().clone())).unwrap()
110} 190}