aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-03-18 18:02:06 +0000
committerAleksey Kladov <[email protected]>2020-03-18 18:34:47 +0000
commit4e50efcfc5fc6e280e638dd446b90e970f7ce699 (patch)
treea80f7620fc7b8c5ed66dba7853634035b5b71312 /crates/ra_syntax
parent12c952f8010afb583989a6e72f81ded4aa9110d2 (diff)
Strongly-typed generic methods for editing nodes
Diffstat (limited to 'crates/ra_syntax')
-rw-r--r--crates/ra_syntax/src/ast/edit.rs96
1 files changed, 49 insertions, 47 deletions
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs
index 40a04b9c5..1e34db5ae 100644
--- a/crates/ra_syntax/src/ast/edit.rs
+++ b/crates/ra_syntax/src/ast/edit.rs
@@ -23,7 +23,7 @@ impl ast::BinExpr {
23 pub fn replace_op(&self, op: SyntaxKind) -> Option<ast::BinExpr> { 23 pub fn replace_op(&self, op: SyntaxKind) -> Option<ast::BinExpr> {
24 let op_node: SyntaxElement = self.op_details()?.0.into(); 24 let op_node: SyntaxElement = self.op_details()?.0.into();
25 let to_insert: Option<SyntaxElement> = Some(make::token(op).into()); 25 let to_insert: Option<SyntaxElement> = Some(make::token(op).into());
26 Some(replace_children(self, single_node(op_node), to_insert)) 26 Some(self.replace_children(single_node(op_node), to_insert))
27 } 27 }
28} 28}
29 29
@@ -39,10 +39,10 @@ impl ast::FnDef {
39 } else { 39 } else {
40 to_insert.push(make::tokens::single_space().into()); 40 to_insert.push(make::tokens::single_space().into());
41 to_insert.push(body.syntax().clone().into()); 41 to_insert.push(body.syntax().clone().into());
42 return insert_children(self, InsertPosition::Last, to_insert); 42 return self.insert_children(InsertPosition::Last, to_insert);
43 }; 43 };
44 to_insert.push(body.syntax().clone().into()); 44 to_insert.push(body.syntax().clone().into());
45 replace_children(self, single_node(old_body_or_semi), to_insert) 45 self.replace_children(single_node(old_body_or_semi), to_insert)
46 } 46 }
47} 47}
48 48
@@ -75,7 +75,7 @@ impl ast::ItemList {
75 let ws = tokens::WsBuilder::new(&format!("\n{}", indent)); 75 let ws = tokens::WsBuilder::new(&format!("\n{}", indent));
76 let to_insert: ArrayVec<[SyntaxElement; 2]> = 76 let to_insert: ArrayVec<[SyntaxElement; 2]> =
77 [ws.ws().into(), item.syntax().clone().into()].into(); 77 [ws.ws().into(), item.syntax().clone().into()].into();
78 insert_children(self, position, to_insert) 78 self.insert_children(position, to_insert)
79 } 79 }
80 80
81 fn l_curly(&self) -> Option<SyntaxElement> { 81 fn l_curly(&self) -> Option<SyntaxElement> {
@@ -106,8 +106,8 @@ impl ast::ItemList {
106 let ws = tokens::WsBuilder::new(&format!("\n{}", indent)); 106 let ws = tokens::WsBuilder::new(&format!("\n{}", indent));
107 let to_insert = iter::once(ws.ws().into()); 107 let to_insert = iter::once(ws.ws().into());
108 match existing_ws { 108 match existing_ws {
109 None => insert_children(self, InsertPosition::After(l_curly), to_insert), 109 None => self.insert_children(InsertPosition::After(l_curly), to_insert),
110 Some(ws) => replace_children(self, single_node(ws), to_insert), 110 Some(ws) => self.replace_children(single_node(ws), to_insert),
111 } 111 }
112 } 112 }
113} 113}
@@ -184,7 +184,7 @@ impl ast::RecordFieldList {
184 InsertPosition::After(anchor) => after_field!(anchor), 184 InsertPosition::After(anchor) => after_field!(anchor),
185 }; 185 };
186 186
187 insert_children(self, position, to_insert) 187 self.insert_children(position, to_insert)
188 } 188 }
189 189
190 fn l_curly(&self) -> Option<SyntaxElement> { 190 fn l_curly(&self) -> Option<SyntaxElement> {
@@ -203,7 +203,7 @@ impl ast::TypeParam {
203 Some(it) => it.syntax().clone().into(), 203 Some(it) => it.syntax().clone().into(),
204 None => colon.clone().into(), 204 None => colon.clone().into(),
205 }; 205 };
206 replace_children(self, colon.into()..=end, iter::empty()) 206 self.replace_children(colon.into()..=end, iter::empty())
207 } 207 }
208} 208}
209 209
@@ -211,8 +211,7 @@ impl ast::Path {
211 #[must_use] 211 #[must_use]
212 pub fn with_segment(&self, segment: ast::PathSegment) -> ast::Path { 212 pub fn with_segment(&self, segment: ast::PathSegment) -> ast::Path {
213 if let Some(old) = self.segment() { 213 if let Some(old) = self.segment() {
214 return replace_children( 214 return self.replace_children(
215 self,
216 single_node(old.syntax().clone()), 215 single_node(old.syntax().clone()),
217 iter::once(segment.syntax().clone().into()), 216 iter::once(segment.syntax().clone().into()),
218 ); 217 );
@@ -234,8 +233,7 @@ impl ast::PathSegment {
234 233
235 fn _with_type_args(&self, type_args: ast::TypeArgList, turbo: bool) -> ast::PathSegment { 234 fn _with_type_args(&self, type_args: ast::TypeArgList, turbo: bool) -> ast::PathSegment {
236 if let Some(old) = self.type_arg_list() { 235 if let Some(old) = self.type_arg_list() {
237 return replace_children( 236 return self.replace_children(
238 self,
239 single_node(old.syntax().clone()), 237 single_node(old.syntax().clone()),
240 iter::once(type_args.syntax().clone().into()), 238 iter::once(type_args.syntax().clone().into()),
241 ); 239 );
@@ -245,7 +243,7 @@ impl ast::PathSegment {
245 to_insert.push(make::token(T![::]).into()); 243 to_insert.push(make::token(T![::]).into());
246 } 244 }
247 to_insert.push(type_args.syntax().clone().into()); 245 to_insert.push(type_args.syntax().clone().into());
248 insert_children(self, InsertPosition::Last, to_insert) 246 self.insert_children(InsertPosition::Last, to_insert)
249 } 247 }
250} 248}
251 249
@@ -253,7 +251,7 @@ impl ast::UseItem {
253 #[must_use] 251 #[must_use]
254 pub fn with_use_tree(&self, use_tree: ast::UseTree) -> ast::UseItem { 252 pub fn with_use_tree(&self, use_tree: ast::UseTree) -> ast::UseItem {
255 if let Some(old) = self.use_tree() { 253 if let Some(old) = self.use_tree() {
256 return replace_descendants(self, iter::once((old, use_tree))); 254 return self.replace_descendants(iter::once((old, use_tree)));
257 } 255 }
258 self.clone() 256 self.clone()
259 } 257 }
@@ -263,7 +261,7 @@ impl ast::UseTree {
263 #[must_use] 261 #[must_use]
264 pub fn with_path(&self, path: ast::Path) -> ast::UseTree { 262 pub fn with_path(&self, path: ast::Path) -> ast::UseTree {
265 if let Some(old) = self.path() { 263 if let Some(old) = self.path() {
266 return replace_descendants(self, iter::once((old, path))); 264 return self.replace_descendants(iter::once((old, path)));
267 } 265 }
268 self.clone() 266 self.clone()
269 } 267 }
@@ -271,7 +269,7 @@ impl ast::UseTree {
271 #[must_use] 269 #[must_use]
272 pub fn with_use_tree_list(&self, use_tree_list: ast::UseTreeList) -> ast::UseTree { 270 pub fn with_use_tree_list(&self, use_tree_list: ast::UseTreeList) -> ast::UseTree {
273 if let Some(old) = self.use_tree_list() { 271 if let Some(old) = self.use_tree_list() {
274 return replace_descendants(self, iter::once((old, use_tree_list))); 272 return self.replace_descendants(iter::once((old, use_tree_list)));
275 } 273 }
276 self.clone() 274 self.clone()
277 } 275 }
@@ -295,19 +293,6 @@ fn strip_attrs_and_docs_inner(mut node: SyntaxNode) -> SyntaxNode {
295 node 293 node
296} 294}
297 295
298#[must_use]
299pub fn replace_descendants<N: AstNode, D: AstNode>(
300 parent: &N,
301 replacement_map: impl IntoIterator<Item = (D, D)>,
302) -> N {
303 let map = replacement_map
304 .into_iter()
305 .map(|(from, to)| (from.syntax().clone().into(), to.syntax().clone().into()))
306 .collect::<FxHashMap<SyntaxElement, _>>();
307 let new_syntax = algo::replace_descendants(parent.syntax(), |n| map.get(n).cloned());
308 N::cast(new_syntax).unwrap()
309}
310
311#[derive(Debug, Clone, Copy)] 296#[derive(Debug, Clone, Copy)]
312pub struct IndentLevel(pub u8); 297pub struct IndentLevel(pub u8);
313 298
@@ -411,31 +396,48 @@ fn prev_tokens(token: SyntaxToken) -> impl Iterator<Item = SyntaxToken> {
411 iter::successors(Some(token), |token| token.prev_token()) 396 iter::successors(Some(token), |token| token.prev_token())
412} 397}
413 398
414#[must_use] 399pub trait AstNodeEdit: AstNode + Sized {
415fn insert_children<N: AstNode>( 400 #[must_use]
416 parent: &N, 401 fn insert_children(
417 position: InsertPosition<SyntaxElement>, 402 &self,
418 to_insert: impl IntoIterator<Item = SyntaxElement>, 403 position: InsertPosition<SyntaxElement>,
419) -> N { 404 to_insert: impl IntoIterator<Item = SyntaxElement>,
420 let new_syntax = algo::insert_children(parent.syntax(), position, to_insert); 405 ) -> Self {
421 N::cast(new_syntax).unwrap() 406 let new_syntax = algo::insert_children(self.syntax(), position, to_insert);
407 Self::cast(new_syntax).unwrap()
408 }
409
410 #[must_use]
411 fn replace_children(
412 &self,
413 to_replace: RangeInclusive<SyntaxElement>,
414 to_insert: impl IntoIterator<Item = SyntaxElement>,
415 ) -> Self {
416 let new_syntax = algo::replace_children(self.syntax(), to_replace, to_insert);
417 Self::cast(new_syntax).unwrap()
418 }
419
420 #[must_use]
421 fn replace_descendants<D: AstNode>(
422 &self,
423 replacement_map: impl IntoIterator<Item = (D, D)>,
424 ) -> Self {
425 let map = replacement_map
426 .into_iter()
427 .map(|(from, to)| (from.syntax().clone().into(), to.syntax().clone().into()))
428 .collect::<FxHashMap<SyntaxElement, _>>();
429 let new_syntax = algo::replace_descendants(self.syntax(), |n| map.get(n).cloned());
430 Self::cast(new_syntax).unwrap()
431 }
422} 432}
423 433
434impl<N: AstNode> AstNodeEdit for N {}
435
424fn single_node(element: impl Into<SyntaxElement>) -> RangeInclusive<SyntaxElement> { 436fn single_node(element: impl Into<SyntaxElement>) -> RangeInclusive<SyntaxElement> {
425 let element = element.into(); 437 let element = element.into();
426 element.clone()..=element 438 element.clone()..=element
427} 439}
428 440
429#[must_use]
430fn replace_children<N: AstNode>(
431 parent: &N,
432 to_replace: RangeInclusive<SyntaxElement>,
433 to_insert: impl IntoIterator<Item = SyntaxElement>,
434) -> N {
435 let new_syntax = algo::replace_children(parent.syntax(), to_replace, to_insert);
436 N::cast(new_syntax).unwrap()
437}
438
439#[test] 441#[test]
440fn test_increase_indent() { 442fn test_increase_indent() {
441 let arm_list = { 443 let arm_list = {