aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax')
-rw-r--r--crates/ra_syntax/src/ast/edit.rs116
-rw-r--r--crates/ra_syntax/src/ast/extensions.rs14
2 files changed, 83 insertions, 47 deletions
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs
index 40a04b9c5..68dae008f 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,10 +269,30 @@ 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 }
276
277 #[must_use]
278 pub fn split_prefix(&self, prefix: &ast::Path) -> ast::UseTree {
279 let suffix = match split_path_prefix(&prefix) {
280 Some(it) => it,
281 None => return self.clone(),
282 };
283 let use_tree = make::use_tree(suffix.clone(), self.use_tree_list(), self.alias());
284 let nested = make::use_tree_list(iter::once(use_tree));
285 return make::use_tree(prefix.clone(), Some(nested), None);
286
287 fn split_path_prefix(prefix: &ast::Path) -> Option<ast::Path> {
288 let parent = prefix.parent_path()?;
289 let mut res = make::path_unqualified(parent.segment()?);
290 for p in iter::successors(parent.parent_path(), |it| it.parent_path()) {
291 res = make::path_qualified(res, p.segment()?);
292 }
293 Some(res)
294 }
295 }
278} 296}
279 297
280#[must_use] 298#[must_use]
@@ -295,19 +313,6 @@ fn strip_attrs_and_docs_inner(mut node: SyntaxNode) -> SyntaxNode {
295 node 313 node
296} 314}
297 315
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)] 316#[derive(Debug, Clone, Copy)]
312pub struct IndentLevel(pub u8); 317pub struct IndentLevel(pub u8);
313 318
@@ -411,31 +416,48 @@ fn prev_tokens(token: SyntaxToken) -> impl Iterator<Item = SyntaxToken> {
411 iter::successors(Some(token), |token| token.prev_token()) 416 iter::successors(Some(token), |token| token.prev_token())
412} 417}
413 418
414#[must_use] 419pub trait AstNodeEdit: AstNode + Sized {
415fn insert_children<N: AstNode>( 420 #[must_use]
416 parent: &N, 421 fn insert_children(
417 position: InsertPosition<SyntaxElement>, 422 &self,
418 to_insert: impl IntoIterator<Item = SyntaxElement>, 423 position: InsertPosition<SyntaxElement>,
419) -> N { 424 to_insert: impl IntoIterator<Item = SyntaxElement>,
420 let new_syntax = algo::insert_children(parent.syntax(), position, to_insert); 425 ) -> Self {
421 N::cast(new_syntax).unwrap() 426 let new_syntax = algo::insert_children(self.syntax(), position, to_insert);
427 Self::cast(new_syntax).unwrap()
428 }
429
430 #[must_use]
431 fn replace_children(
432 &self,
433 to_replace: RangeInclusive<SyntaxElement>,
434 to_insert: impl IntoIterator<Item = SyntaxElement>,
435 ) -> Self {
436 let new_syntax = algo::replace_children(self.syntax(), to_replace, to_insert);
437 Self::cast(new_syntax).unwrap()
438 }
439
440 #[must_use]
441 fn replace_descendants<D: AstNode>(
442 &self,
443 replacement_map: impl IntoIterator<Item = (D, D)>,
444 ) -> Self {
445 let map = replacement_map
446 .into_iter()
447 .map(|(from, to)| (from.syntax().clone().into(), to.syntax().clone().into()))
448 .collect::<FxHashMap<SyntaxElement, _>>();
449 let new_syntax = algo::replace_descendants(self.syntax(), |n| map.get(n).cloned());
450 Self::cast(new_syntax).unwrap()
451 }
422} 452}
423 453
454impl<N: AstNode> AstNodeEdit for N {}
455
424fn single_node(element: impl Into<SyntaxElement>) -> RangeInclusive<SyntaxElement> { 456fn single_node(element: impl Into<SyntaxElement>) -> RangeInclusive<SyntaxElement> {
425 let element = element.into(); 457 let element = element.into();
426 element.clone()..=element 458 element.clone()..=element
427} 459}
428 460
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] 461#[test]
440fn test_increase_indent() { 462fn test_increase_indent() {
441 let arm_list = { 463 let arm_list = {
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs
index d5986e8b4..c3ae8f90e 100644
--- a/crates/ra_syntax/src/ast/extensions.rs
+++ b/crates/ra_syntax/src/ast/extensions.rs
@@ -167,6 +167,20 @@ impl ast::UseTreeList {
167 .and_then(ast::UseTree::cast) 167 .and_then(ast::UseTree::cast)
168 .expect("UseTreeLists are always nested in UseTrees") 168 .expect("UseTreeLists are always nested in UseTrees")
169 } 169 }
170 pub fn l_curly(&self) -> Option<SyntaxToken> {
171 self.token(T!['{'])
172 }
173
174 pub fn r_curly(&self) -> Option<SyntaxToken> {
175 self.token(T!['}'])
176 }
177
178 fn token(&self, kind: SyntaxKind) -> Option<SyntaxToken> {
179 self.syntax()
180 .children_with_tokens()
181 .filter_map(|it| it.into_token())
182 .find(|it| it.kind() == kind)
183 }
170} 184}
171 185
172impl ast::ImplDef { 186impl ast::ImplDef {