diff options
Diffstat (limited to 'crates/ra_syntax')
-rw-r--r-- | crates/ra_syntax/src/ast/edit.rs | 116 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/extensions.rs | 14 | ||||
-rw-r--r-- | crates/ra_syntax/src/lib.rs | 4 |
3 files changed, 85 insertions, 49 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] | ||
299 | pub 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)] |
312 | pub struct IndentLevel(pub u8); | 317 | pub 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] | 419 | pub trait AstNodeEdit: AstNode + Sized { |
415 | fn 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 | ||
454 | impl<N: AstNode> AstNodeEdit for N {} | ||
455 | |||
424 | fn single_node(element: impl Into<SyntaxElement>) -> RangeInclusive<SyntaxElement> { | 456 | fn 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] | ||
430 | fn 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] |
440 | fn test_increase_indent() { | 462 | fn 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 | ||
172 | impl ast::ImplDef { | 186 | impl ast::ImplDef { |
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index e3f74da6d..cef926ed3 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs | |||
@@ -179,10 +179,10 @@ macro_rules! match_ast { | |||
179 | (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) }; | 179 | (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) }; |
180 | 180 | ||
181 | (match ($node:expr) { | 181 | (match ($node:expr) { |
182 | $( ast::$ast:ident($it:ident) => $res:block, )* | 182 | $( ast::$ast:ident($it:ident) => $res:expr, )* |
183 | _ => $catch_all:expr $(,)? | 183 | _ => $catch_all:expr $(,)? |
184 | }) => {{ | 184 | }) => {{ |
185 | $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )* | 185 | $( if let Some($it) = ast::$ast::cast($node.clone()) { $res } else )* |
186 | { $catch_all } | 186 | { $catch_all } |
187 | }}; | 187 | }}; |
188 | } | 188 | } |