aboutsummaryrefslogtreecommitdiff
path: root/crates/syntax/src/ast/edit.rs
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-05-14 16:54:38 +0100
committerGitHub <[email protected]>2021-05-14 16:54:38 +0100
commita32589f773be2c19e6b6307b5302d07ec3ab6db6 (patch)
tree3a6f291d7396ef77dfe8114a21a749f7dfa96b03 /crates/syntax/src/ast/edit.rs
parent73123a7550a667ebc42be96651a8e36be482a828 (diff)
parent6c21d04307edf130851aefad406bacce9edbde23 (diff)
Merge #8837
8837: internal: rewrite assoc item manipulaion to use mutable trees r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/syntax/src/ast/edit.rs')
-rw-r--r--crates/syntax/src/ast/edit.rs151
1 files changed, 6 insertions, 145 deletions
diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs
index 10ec94cd2..7e4b8252e 100644
--- a/crates/syntax/src/ast/edit.rs
+++ b/crates/syntax/src/ast/edit.rs
@@ -80,81 +80,6 @@ where
80 } 80 }
81} 81}
82 82
83impl ast::Impl {
84 #[must_use]
85 pub fn with_assoc_item_list(&self, items: ast::AssocItemList) -> ast::Impl {
86 let mut to_insert: ArrayVec<SyntaxElement, 2> = ArrayVec::new();
87 if let Some(old_items) = self.assoc_item_list() {
88 let to_replace: SyntaxElement = old_items.syntax().clone().into();
89 to_insert.push(items.syntax().clone().into());
90 self.replace_children(single_node(to_replace), to_insert)
91 } else {
92 to_insert.push(make::tokens::single_space().into());
93 to_insert.push(items.syntax().clone().into());
94 self.insert_children(InsertPosition::Last, to_insert)
95 }
96 }
97}
98
99impl ast::AssocItemList {
100 #[must_use]
101 pub fn append_items(
102 &self,
103 items: impl IntoIterator<Item = ast::AssocItem>,
104 ) -> ast::AssocItemList {
105 let mut res = self.clone();
106 if !self.syntax().text().contains_char('\n') {
107 res = make_multiline(res);
108 }
109 items.into_iter().for_each(|it| res = res.append_item(it));
110 res.fixup_trailing_whitespace().unwrap_or(res)
111 }
112
113 #[must_use]
114 pub fn append_item(&self, item: ast::AssocItem) -> ast::AssocItemList {
115 let (indent, position, whitespace) = match self.assoc_items().last() {
116 Some(it) => (
117 leading_indent(it.syntax()).unwrap_or_default().to_string(),
118 InsertPosition::After(it.syntax().clone().into()),
119 "\n\n",
120 ),
121 None => match self.l_curly_token() {
122 Some(it) => (
123 " ".to_string() + &leading_indent(self.syntax()).unwrap_or_default(),
124 InsertPosition::After(it.into()),
125 "\n",
126 ),
127 None => return self.clone(),
128 },
129 };
130 let ws = tokens::WsBuilder::new(&format!("{}{}", whitespace, indent));
131 let to_insert: ArrayVec<SyntaxElement, 2> =
132 [ws.ws().into(), item.syntax().clone().into()].into();
133 self.insert_children(position, to_insert)
134 }
135
136 /// Remove extra whitespace between last item and closing curly brace.
137 fn fixup_trailing_whitespace(&self) -> Option<ast::AssocItemList> {
138 let first_token_after_items =
139 self.assoc_items().last()?.syntax().next_sibling_or_token()?;
140 let last_token_before_curly = self.r_curly_token()?.prev_sibling_or_token()?;
141 if last_token_before_curly != first_token_after_items {
142 // there is something more between last item and
143 // right curly than just whitespace - bail out
144 return None;
145 }
146 let whitespace =
147 last_token_before_curly.clone().into_token().and_then(ast::Whitespace::cast)?;
148 let text = whitespace.syntax().text();
149 let newline = text.rfind('\n')?;
150 let keep = tokens::WsBuilder::new(&text[newline..]);
151 Some(self.replace_children(
152 first_token_after_items..=last_token_before_curly,
153 std::iter::once(keep.ws().into()),
154 ))
155 }
156}
157
158impl ast::RecordExprFieldList { 83impl ast::RecordExprFieldList {
159 #[must_use] 84 #[must_use]
160 pub fn append_field(&self, field: &ast::RecordExprField) -> ast::RecordExprFieldList { 85 pub fn append_field(&self, field: &ast::RecordExprField) -> ast::RecordExprFieldList {
@@ -246,21 +171,6 @@ impl ast::TypeAlias {
246 } 171 }
247} 172}
248 173
249impl ast::TypeParam {
250 #[must_use]
251 pub fn remove_bounds(&self) -> ast::TypeParam {
252 let colon = match self.colon_token() {
253 Some(it) => it,
254 None => return self.clone(),
255 };
256 let end = match self.type_bound_list() {
257 Some(it) => it.syntax().clone().into(),
258 None => colon.clone().into(),
259 };
260 self.replace_children(colon.into()..=end, iter::empty())
261 }
262}
263
264impl ast::Path { 174impl ast::Path {
265 #[must_use] 175 #[must_use]
266 pub fn with_segment(&self, segment: ast::PathSegment) -> ast::Path { 176 pub fn with_segment(&self, segment: ast::PathSegment) -> ast::Path {
@@ -411,61 +321,6 @@ impl ast::MatchArmList {
411 } 321 }
412} 322}
413 323
414impl ast::GenericParamList {
415 #[must_use]
416 pub fn append_params(
417 &self,
418 params: impl IntoIterator<Item = ast::GenericParam>,
419 ) -> ast::GenericParamList {
420 let mut res = self.clone();
421 params.into_iter().for_each(|it| res = res.append_param(it));
422 res
423 }
424
425 #[must_use]
426 pub fn append_param(&self, item: ast::GenericParam) -> ast::GenericParamList {
427 let space = tokens::single_space();
428
429 let mut to_insert: ArrayVec<SyntaxElement, 4> = ArrayVec::new();
430 if self.generic_params().next().is_some() {
431 to_insert.push(space.into());
432 }
433 to_insert.push(item.syntax().clone().into());
434
435 macro_rules! after_l_angle {
436 () => {{
437 let anchor = match self.l_angle_token() {
438 Some(it) => it.into(),
439 None => return self.clone(),
440 };
441 InsertPosition::After(anchor)
442 }};
443 }
444
445 macro_rules! after_field {
446 ($anchor:expr) => {
447 if let Some(comma) = $anchor
448 .syntax()
449 .siblings_with_tokens(Direction::Next)
450 .find(|it| it.kind() == T![,])
451 {
452 InsertPosition::After(comma)
453 } else {
454 to_insert.insert(0, make::token(T![,]).into());
455 InsertPosition::After($anchor.syntax().clone().into())
456 }
457 };
458 }
459
460 let position = match self.generic_params().last() {
461 Some(it) => after_field!(it),
462 None => after_l_angle!(),
463 };
464
465 self.insert_children(position, to_insert)
466 }
467}
468
469#[must_use] 324#[must_use]
470pub fn remove_attrs_and_docs<N: ast::AttrsOwner>(node: &N) -> N { 325pub fn remove_attrs_and_docs<N: ast::AttrsOwner>(node: &N) -> N {
471 N::cast(remove_attrs_and_docs_inner(node.syntax().clone())).unwrap() 326 N::cast(remove_attrs_and_docs_inner(node.syntax().clone())).unwrap()
@@ -516,6 +371,12 @@ impl ops::Add<u8> for IndentLevel {
516} 371}
517 372
518impl IndentLevel { 373impl IndentLevel {
374 pub fn single() -> IndentLevel {
375 IndentLevel(0)
376 }
377 pub fn is_zero(&self) -> bool {
378 self.0 == 0
379 }
519 pub fn from_element(element: &SyntaxElement) -> IndentLevel { 380 pub fn from_element(element: &SyntaxElement) -> IndentLevel {
520 match element { 381 match element {
521 rowan::NodeOrToken::Node(it) => IndentLevel::from_node(it), 382 rowan::NodeOrToken::Node(it) => IndentLevel::from_node(it),