aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax
diff options
context:
space:
mode:
authorMatthew Hall <[email protected]>2020-03-28 20:44:12 +0000
committerMatthew Hall <[email protected]>2020-03-28 20:58:46 +0000
commitecc2615ba2da0e083a8dbfbf203d1fd7fe0bcaaf (patch)
treee35cea1b482c65b98e1025da47e9670df61e92ed /crates/ra_syntax
parent1c2d4135db867efe335a0654d86429bea7bb9caf (diff)
Append new match arms rather than replacing all of them
This means we now retain comments when filling in match arms.
Diffstat (limited to 'crates/ra_syntax')
-rw-r--r--crates/ra_syntax/src/ast/edit.rs142
1 files changed, 112 insertions, 30 deletions
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs
index 2304e00cf..437186888 100644
--- a/crates/ra_syntax/src/ast/edit.rs
+++ b/crates/ra_syntax/src/ast/edit.rs
@@ -46,12 +46,44 @@ impl ast::FnDef {
46 } 46 }
47} 47}
48 48
49fn make_multiline<N>(node: N) -> N
50where
51 N: AstNode + Clone,
52{
53 let l_curly = match node.syntax().children_with_tokens().find(|it| it.kind() == T!['{']) {
54 Some(it) => it,
55 None => return node,
56 };
57 let sibling = match l_curly.next_sibling_or_token() {
58 Some(it) => it,
59 None => return node,
60 };
61 let existing_ws = match sibling.as_token() {
62 None => None,
63 Some(tok) if tok.kind() != WHITESPACE => None,
64 Some(ws) => {
65 if ws.text().contains('\n') {
66 return node;
67 }
68 Some(ws.clone())
69 }
70 };
71
72 let indent = leading_indent(node.syntax()).unwrap_or_default();
73 let ws = tokens::WsBuilder::new(&format!("\n{}", indent));
74 let to_insert = iter::once(ws.ws().into());
75 match existing_ws {
76 None => node.insert_children(InsertPosition::After(l_curly), to_insert),
77 Some(ws) => node.replace_children(single_node(ws), to_insert),
78 }
79}
80
49impl ast::ItemList { 81impl ast::ItemList {
50 #[must_use] 82 #[must_use]
51 pub fn append_items(&self, items: impl Iterator<Item = ast::ImplItem>) -> ast::ItemList { 83 pub fn append_items(&self, items: impl Iterator<Item = ast::ImplItem>) -> ast::ItemList {
52 let mut res = self.clone(); 84 let mut res = self.clone();
53 if !self.syntax().text().contains_char('\n') { 85 if !self.syntax().text().contains_char('\n') {
54 res = res.make_multiline(); 86 res = make_multiline(res);
55 } 87 }
56 items.for_each(|it| res = res.append_item(it)); 88 items.for_each(|it| res = res.append_item(it));
57 res 89 res
@@ -81,35 +113,6 @@ impl ast::ItemList {
81 fn l_curly(&self) -> Option<SyntaxElement> { 113 fn l_curly(&self) -> Option<SyntaxElement> {
82 self.syntax().children_with_tokens().find(|it| it.kind() == T!['{']) 114 self.syntax().children_with_tokens().find(|it| it.kind() == T!['{'])
83 } 115 }
84
85 fn make_multiline(&self) -> ast::ItemList {
86 let l_curly = match self.syntax().children_with_tokens().find(|it| it.kind() == T!['{']) {
87 Some(it) => it,
88 None => return self.clone(),
89 };
90 let sibling = match l_curly.next_sibling_or_token() {
91 Some(it) => it,
92 None => return self.clone(),
93 };
94 let existing_ws = match sibling.as_token() {
95 None => None,
96 Some(tok) if tok.kind() != WHITESPACE => None,
97 Some(ws) => {
98 if ws.text().contains('\n') {
99 return self.clone();
100 }
101 Some(ws.clone())
102 }
103 };
104
105 let indent = leading_indent(self.syntax()).unwrap_or_default();
106 let ws = tokens::WsBuilder::new(&format!("\n{}", indent));
107 let to_insert = iter::once(ws.ws().into());
108 match existing_ws {
109 None => self.insert_children(InsertPosition::After(l_curly), to_insert),
110 Some(ws) => self.replace_children(single_node(ws), to_insert),
111 }
112 }
113} 116}
114 117
115impl ast::RecordFieldList { 118impl ast::RecordFieldList {
@@ -334,6 +337,85 @@ impl ast::UseTree {
334 } 337 }
335} 338}
336 339
340impl ast::MatchArmList {
341 #[must_use]
342 pub fn append_arms(&self, items: impl Iterator<Item = ast::MatchArm>) -> ast::MatchArmList {
343 let mut res = self.clone();
344 res = res.strip_if_only_whitespace();
345 if !res.syntax().text().contains_char('\n') {
346 res = make_multiline(res);
347 }
348 items.for_each(|it| res = res.append_arm(it));
349 res
350 }
351
352 fn strip_if_only_whitespace(&self) -> ast::MatchArmList {
353 let mut iter = self.syntax().children_with_tokens().skip_while(|it| it.kind() != T!['{']);
354 iter.next(); // Eat the curly
355 let mut inner = iter.take_while(|it| it.kind() != T!['}']);
356 if !inner.clone().all(|it| it.kind() == WHITESPACE) {
357 return self.clone();
358 }
359 let start = match inner.next() {
360 Some(s) => s,
361 None => return self.clone(),
362 };
363 let end = match inner.last() {
364 Some(s) => s,
365 None => start.clone(),
366 };
367 let res = self.replace_children(start..=end, &mut iter::empty());
368 res
369 }
370
371 #[must_use]
372 pub fn remove_placeholder(&self) -> ast::MatchArmList {
373 let placeholder = self.arms().find(|arm| {
374 if let Some(ast::Pat::PlaceholderPat(_)) = arm.pat() {
375 return true;
376 }
377 false
378 });
379 if let Some(placeholder) = placeholder {
380 let s: SyntaxElement = placeholder.syntax().clone().into();
381 let e = s.clone();
382 self.replace_children(s..=e, &mut iter::empty())
383 } else {
384 self.clone()
385 }
386 }
387
388 #[must_use]
389 pub fn append_arm(&self, item: ast::MatchArm) -> ast::MatchArmList {
390 let r_curly = match self.syntax().children_with_tokens().find(|it| it.kind() == T!['}']) {
391 Some(t) => t,
392 None => return self.clone(),
393 };
394 let mut sib = r_curly.prev_sibling_or_token();
395 while let Some(s) = sib.clone() {
396 if let Some(tok) = s.as_token() {
397 if tok.kind() != WHITESPACE {
398 break;
399 }
400 sib = s.prev_sibling_or_token();
401 } else {
402 break;
403 }
404 }
405 let indent = " ".to_string() + &leading_indent(self.syntax()).unwrap_or_default();
406 let sib = match sib {
407 Some(s) => s,
408 None => return self.clone(),
409 };
410 let position = InsertPosition::After(sib.into());
411 let ws = tokens::WsBuilder::new(&format!("\n{}", indent));
412 let to_insert: ArrayVec<[SyntaxElement; 2]> =
413 [ws.ws().into(), item.syntax().clone().into()].into();
414 let res = self.insert_children(position, to_insert);
415 res
416 }
417}
418
337#[must_use] 419#[must_use]
338pub fn remove_attrs_and_docs<N: ast::AttrsOwner>(node: &N) -> N { 420pub fn remove_attrs_and_docs<N: ast::AttrsOwner>(node: &N) -> N {
339 N::cast(remove_attrs_and_docs_inner(node.syntax().clone())).unwrap() 421 N::cast(remove_attrs_and_docs_inner(node.syntax().clone())).unwrap()