diff options
author | jDomantas <[email protected]> | 2020-08-14 14:10:52 +0100 |
---|---|---|
committer | jDomantas <[email protected]> | 2020-08-14 14:10:52 +0100 |
commit | 9f548a02957314819aa0530d01f7c4a27dffdfc8 (patch) | |
tree | bb3502c55790678c57118a4fbff36b42ebc78e06 | |
parent | 1ec23e7d33e29c6e14f4fe504e1e253e91339ea4 (diff) |
fixup whitespace when adding missing impl items
-rw-r--r-- | crates/assists/src/handlers/add_missing_impl_members.rs | 63 | ||||
-rw-r--r-- | crates/syntax/src/ast/edit.rs | 33 |
2 files changed, 89 insertions, 7 deletions
diff --git a/crates/assists/src/handlers/add_missing_impl_members.rs b/crates/assists/src/handlers/add_missing_impl_members.rs index 81b61ebf8..83a2ada9a 100644 --- a/crates/assists/src/handlers/add_missing_impl_members.rs +++ b/crates/assists/src/handlers/add_missing_impl_members.rs | |||
@@ -48,7 +48,6 @@ enum AddMissingImplMembersMode { | |||
48 | // fn foo(&self) -> u32 { | 48 | // fn foo(&self) -> u32 { |
49 | // ${0:todo!()} | 49 | // ${0:todo!()} |
50 | // } | 50 | // } |
51 | // | ||
52 | // } | 51 | // } |
53 | // ``` | 52 | // ``` |
54 | pub(crate) fn add_missing_impl_members(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 53 | pub(crate) fn add_missing_impl_members(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
@@ -89,8 +88,8 @@ pub(crate) fn add_missing_impl_members(acc: &mut Assists, ctx: &AssistContext) - | |||
89 | // impl Trait for () { | 88 | // impl Trait for () { |
90 | // Type X = (); | 89 | // Type X = (); |
91 | // fn foo(&self) {} | 90 | // fn foo(&self) {} |
92 | // $0fn bar(&self) {} | ||
93 | // | 91 | // |
92 | // $0fn bar(&self) {} | ||
94 | // } | 93 | // } |
95 | // ``` | 94 | // ``` |
96 | pub(crate) fn add_missing_default_members(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 95 | pub(crate) fn add_missing_default_members(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
@@ -240,15 +239,18 @@ struct S; | |||
240 | 239 | ||
241 | impl Foo for S { | 240 | impl Foo for S { |
242 | fn bar(&self) {} | 241 | fn bar(&self) {} |
242 | |||
243 | $0type Output; | 243 | $0type Output; |
244 | |||
244 | const CONST: usize = 42; | 245 | const CONST: usize = 42; |
246 | |||
245 | fn foo(&self) { | 247 | fn foo(&self) { |
246 | todo!() | 248 | todo!() |
247 | } | 249 | } |
250 | |||
248 | fn baz(&self) { | 251 | fn baz(&self) { |
249 | todo!() | 252 | todo!() |
250 | } | 253 | } |
251 | |||
252 | }"#, | 254 | }"#, |
253 | ); | 255 | ); |
254 | } | 256 | } |
@@ -281,10 +283,10 @@ struct S; | |||
281 | 283 | ||
282 | impl Foo for S { | 284 | impl Foo for S { |
283 | fn bar(&self) {} | 285 | fn bar(&self) {} |
286 | |||
284 | fn foo(&self) { | 287 | fn foo(&self) { |
285 | ${0:todo!()} | 288 | ${0:todo!()} |
286 | } | 289 | } |
287 | |||
288 | }"#, | 290 | }"#, |
289 | ); | 291 | ); |
290 | } | 292 | } |
@@ -599,6 +601,7 @@ trait Foo { | |||
599 | struct S; | 601 | struct S; |
600 | impl Foo for S { | 602 | impl Foo for S { |
601 | $0type Output; | 603 | $0type Output; |
604 | |||
602 | fn foo(&self) { | 605 | fn foo(&self) { |
603 | todo!() | 606 | todo!() |
604 | } | 607 | } |
@@ -708,4 +711,56 @@ impl Tr for () { | |||
708 | }"#, | 711 | }"#, |
709 | ) | 712 | ) |
710 | } | 713 | } |
714 | |||
715 | #[test] | ||
716 | fn test_whitespace_fixup_preserves_bad_tokens() { | ||
717 | check_assist( | ||
718 | add_missing_impl_members, | ||
719 | r#" | ||
720 | trait Tr { | ||
721 | fn foo(); | ||
722 | } | ||
723 | |||
724 | impl Tr for ()<|> { | ||
725 | +++ | ||
726 | }"#, | ||
727 | r#" | ||
728 | trait Tr { | ||
729 | fn foo(); | ||
730 | } | ||
731 | |||
732 | impl Tr for () { | ||
733 | fn foo() { | ||
734 | ${0:todo!()} | ||
735 | } | ||
736 | +++ | ||
737 | }"#, | ||
738 | ) | ||
739 | } | ||
740 | |||
741 | #[test] | ||
742 | fn test_whitespace_fixup_preserves_comments() { | ||
743 | check_assist( | ||
744 | add_missing_impl_members, | ||
745 | r#" | ||
746 | trait Tr { | ||
747 | fn foo(); | ||
748 | } | ||
749 | |||
750 | impl Tr for ()<|> { | ||
751 | // very important | ||
752 | }"#, | ||
753 | r#" | ||
754 | trait Tr { | ||
755 | fn foo(); | ||
756 | } | ||
757 | |||
758 | impl Tr for () { | ||
759 | fn foo() { | ||
760 | ${0:todo!()} | ||
761 | } | ||
762 | // very important | ||
763 | }"#, | ||
764 | ) | ||
765 | } | ||
711 | } | 766 | } |
diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs index 190746e09..b295b5bc6 100644 --- a/crates/syntax/src/ast/edit.rs +++ b/crates/syntax/src/ast/edit.rs | |||
@@ -91,29 +91,56 @@ impl ast::AssocItemList { | |||
91 | res = make_multiline(res); | 91 | res = make_multiline(res); |
92 | } | 92 | } |
93 | items.into_iter().for_each(|it| res = res.append_item(it)); | 93 | items.into_iter().for_each(|it| res = res.append_item(it)); |
94 | res | 94 | res.fixup_trailing_whitespace().unwrap_or(res) |
95 | } | 95 | } |
96 | 96 | ||
97 | #[must_use] | 97 | #[must_use] |
98 | pub fn append_item(&self, item: ast::AssocItem) -> ast::AssocItemList { | 98 | pub fn append_item(&self, item: ast::AssocItem) -> ast::AssocItemList { |
99 | let (indent, position) = match self.assoc_items().last() { | 99 | let (indent, position, whitespace) = match self.assoc_items().last() { |
100 | Some(it) => ( | 100 | Some(it) => ( |
101 | leading_indent(it.syntax()).unwrap_or_default().to_string(), | 101 | leading_indent(it.syntax()).unwrap_or_default().to_string(), |
102 | InsertPosition::After(it.syntax().clone().into()), | 102 | InsertPosition::After(it.syntax().clone().into()), |
103 | "\n\n", | ||
103 | ), | 104 | ), |
104 | None => match self.l_curly_token() { | 105 | None => match self.l_curly_token() { |
105 | Some(it) => ( | 106 | Some(it) => ( |
106 | " ".to_string() + &leading_indent(self.syntax()).unwrap_or_default(), | 107 | " ".to_string() + &leading_indent(self.syntax()).unwrap_or_default(), |
107 | InsertPosition::After(it.into()), | 108 | InsertPosition::After(it.into()), |
109 | "\n", | ||
108 | ), | 110 | ), |
109 | None => return self.clone(), | 111 | None => return self.clone(), |
110 | }, | 112 | }, |
111 | }; | 113 | }; |
112 | let ws = tokens::WsBuilder::new(&format!("\n{}", indent)); | 114 | let ws = tokens::WsBuilder::new(&format!("{}{}", whitespace, indent)); |
113 | let to_insert: ArrayVec<[SyntaxElement; 2]> = | 115 | let to_insert: ArrayVec<[SyntaxElement; 2]> = |
114 | [ws.ws().into(), item.syntax().clone().into()].into(); | 116 | [ws.ws().into(), item.syntax().clone().into()].into(); |
115 | self.insert_children(position, to_insert) | 117 | self.insert_children(position, to_insert) |
116 | } | 118 | } |
119 | |||
120 | /// Remove extra whitespace between last item and closing curly brace. | ||
121 | fn fixup_trailing_whitespace(&self) -> Option<ast::AssocItemList> { | ||
122 | let first_token_after_items = self | ||
123 | .assoc_items() | ||
124 | .last()? | ||
125 | .syntax() | ||
126 | .next_sibling_or_token()?; | ||
127 | let last_token_before_curly = self | ||
128 | .r_curly_token()? | ||
129 | .prev_sibling_or_token()?; | ||
130 | if last_token_before_curly != first_token_after_items { | ||
131 | // there is something more between last item and | ||
132 | // right curly than just whitespace - bail out | ||
133 | return None; | ||
134 | } | ||
135 | let whitespace = last_token_before_curly | ||
136 | .clone() | ||
137 | .into_token() | ||
138 | .and_then(ast::Whitespace::cast)?; | ||
139 | let text = whitespace.syntax().text(); | ||
140 | let newline = text.rfind("\n")?; | ||
141 | let keep = tokens::WsBuilder::new(&text[newline..]); | ||
142 | Some(self.replace_children(first_token_after_items..=last_token_before_curly, std::iter::once(keep.ws().into()))) | ||
143 | } | ||
117 | } | 144 | } |
118 | 145 | ||
119 | impl ast::RecordExprFieldList { | 146 | impl ast::RecordExprFieldList { |