diff options
Diffstat (limited to 'crates/ra_syntax/src/ast')
-rw-r--r-- | crates/ra_syntax/src/ast/edit.rs | 109 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/extensions.rs | 13 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/make.rs | 17 |
3 files changed, 97 insertions, 42 deletions
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs index 68dae008f..f74c9f9c6 100644 --- a/crates/ra_syntax/src/ast/edit.rs +++ b/crates/ra_syntax/src/ast/edit.rs | |||
@@ -4,7 +4,6 @@ | |||
4 | use std::{iter, ops::RangeInclusive}; | 4 | use std::{iter, ops::RangeInclusive}; |
5 | 5 | ||
6 | use arrayvec::ArrayVec; | 6 | use arrayvec::ArrayVec; |
7 | use rustc_hash::FxHashMap; | ||
8 | 7 | ||
9 | use crate::{ | 8 | use crate::{ |
10 | algo, | 9 | algo, |
@@ -17,6 +16,7 @@ use crate::{ | |||
17 | SyntaxKind::{ATTR, COMMENT, WHITESPACE}, | 16 | SyntaxKind::{ATTR, COMMENT, WHITESPACE}, |
18 | SyntaxNode, SyntaxToken, T, | 17 | SyntaxNode, SyntaxToken, T, |
19 | }; | 18 | }; |
19 | use algo::{neighbor, SyntaxRewriter}; | ||
20 | 20 | ||
21 | impl ast::BinExpr { | 21 | impl ast::BinExpr { |
22 | #[must_use] | 22 | #[must_use] |
@@ -255,6 +255,28 @@ impl ast::UseItem { | |||
255 | } | 255 | } |
256 | self.clone() | 256 | self.clone() |
257 | } | 257 | } |
258 | |||
259 | pub fn remove(&self) -> SyntaxRewriter<'static> { | ||
260 | let mut res = SyntaxRewriter::default(); | ||
261 | res.delete(self.syntax()); | ||
262 | let next_ws = self | ||
263 | .syntax() | ||
264 | .next_sibling_or_token() | ||
265 | .and_then(|it| it.into_token()) | ||
266 | .and_then(ast::Whitespace::cast); | ||
267 | if let Some(next_ws) = next_ws { | ||
268 | let ws_text = next_ws.syntax().text(); | ||
269 | if ws_text.starts_with('\n') { | ||
270 | let rest = &ws_text[1..]; | ||
271 | if rest.is_empty() { | ||
272 | res.delete(next_ws.syntax()) | ||
273 | } else { | ||
274 | res.replace(next_ws.syntax(), &make::tokens::whitespace(rest)); | ||
275 | } | ||
276 | } | ||
277 | } | ||
278 | res | ||
279 | } | ||
258 | } | 280 | } |
259 | 281 | ||
260 | impl ast::UseTree { | 282 | impl ast::UseTree { |
@@ -293,14 +315,30 @@ impl ast::UseTree { | |||
293 | Some(res) | 315 | Some(res) |
294 | } | 316 | } |
295 | } | 317 | } |
318 | |||
319 | pub fn remove(&self) -> SyntaxRewriter<'static> { | ||
320 | let mut res = SyntaxRewriter::default(); | ||
321 | res.delete(self.syntax()); | ||
322 | for &dir in [Direction::Next, Direction::Prev].iter() { | ||
323 | if let Some(nb) = neighbor(self, dir) { | ||
324 | self.syntax() | ||
325 | .siblings_with_tokens(dir) | ||
326 | .skip(1) | ||
327 | .take_while(|it| it.as_node() != Some(nb.syntax())) | ||
328 | .for_each(|el| res.delete(&el)); | ||
329 | return res; | ||
330 | } | ||
331 | } | ||
332 | res | ||
333 | } | ||
296 | } | 334 | } |
297 | 335 | ||
298 | #[must_use] | 336 | #[must_use] |
299 | pub fn strip_attrs_and_docs<N: ast::AttrsOwner>(node: &N) -> N { | 337 | pub fn remove_attrs_and_docs<N: ast::AttrsOwner>(node: &N) -> N { |
300 | N::cast(strip_attrs_and_docs_inner(node.syntax().clone())).unwrap() | 338 | N::cast(remove_attrs_and_docs_inner(node.syntax().clone())).unwrap() |
301 | } | 339 | } |
302 | 340 | ||
303 | fn strip_attrs_and_docs_inner(mut node: SyntaxNode) -> SyntaxNode { | 341 | fn remove_attrs_and_docs_inner(mut node: SyntaxNode) -> SyntaxNode { |
304 | while let Some(start) = | 342 | while let Some(start) = |
305 | node.children_with_tokens().find(|it| it.kind() == ATTR || it.kind() == COMMENT) | 343 | node.children_with_tokens().find(|it| it.kind() == ATTR || it.kind() == COMMENT) |
306 | { | 344 | { |
@@ -343,28 +381,24 @@ impl IndentLevel { | |||
343 | } | 381 | } |
344 | 382 | ||
345 | fn _increase_indent(self, node: SyntaxNode) -> SyntaxNode { | 383 | fn _increase_indent(self, node: SyntaxNode) -> SyntaxNode { |
346 | let replacements: FxHashMap<SyntaxElement, SyntaxElement> = node | 384 | let mut rewriter = SyntaxRewriter::default(); |
347 | .descendants_with_tokens() | 385 | node.descendants_with_tokens() |
348 | .filter_map(|el| el.into_token()) | 386 | .filter_map(|el| el.into_token()) |
349 | .filter_map(ast::Whitespace::cast) | 387 | .filter_map(ast::Whitespace::cast) |
350 | .filter(|ws| { | 388 | .filter(|ws| { |
351 | let text = ws.syntax().text(); | 389 | let text = ws.syntax().text(); |
352 | text.contains('\n') | 390 | text.contains('\n') |
353 | }) | 391 | }) |
354 | .map(|ws| { | 392 | .for_each(|ws| { |
355 | ( | 393 | let new_ws = make::tokens::whitespace(&format!( |
356 | ws.syntax().clone().into(), | 394 | "{}{:width$}", |
357 | make::tokens::whitespace(&format!( | 395 | ws.syntax().text(), |
358 | "{}{:width$}", | 396 | "", |
359 | ws.syntax().text(), | 397 | width = self.0 as usize * 4 |
360 | "", | 398 | )); |
361 | width = self.0 as usize * 4 | 399 | rewriter.replace(ws.syntax(), &new_ws) |
362 | )) | 400 | }); |
363 | .into(), | 401 | rewriter.rewrite(&node) |
364 | ) | ||
365 | }) | ||
366 | .collect(); | ||
367 | algo::replace_descendants(&node, |n| replacements.get(n).cloned()) | ||
368 | } | 402 | } |
369 | 403 | ||
370 | pub fn decrease_indent<N: AstNode>(self, node: N) -> N { | 404 | pub fn decrease_indent<N: AstNode>(self, node: N) -> N { |
@@ -372,27 +406,21 @@ impl IndentLevel { | |||
372 | } | 406 | } |
373 | 407 | ||
374 | fn _decrease_indent(self, node: SyntaxNode) -> SyntaxNode { | 408 | fn _decrease_indent(self, node: SyntaxNode) -> SyntaxNode { |
375 | let replacements: FxHashMap<SyntaxElement, SyntaxElement> = node | 409 | let mut rewriter = SyntaxRewriter::default(); |
376 | .descendants_with_tokens() | 410 | node.descendants_with_tokens() |
377 | .filter_map(|el| el.into_token()) | 411 | .filter_map(|el| el.into_token()) |
378 | .filter_map(ast::Whitespace::cast) | 412 | .filter_map(ast::Whitespace::cast) |
379 | .filter(|ws| { | 413 | .filter(|ws| { |
380 | let text = ws.syntax().text(); | 414 | let text = ws.syntax().text(); |
381 | text.contains('\n') | 415 | text.contains('\n') |
382 | }) | 416 | }) |
383 | .map(|ws| { | 417 | .for_each(|ws| { |
384 | ( | 418 | let new_ws = make::tokens::whitespace( |
385 | ws.syntax().clone().into(), | 419 | &ws.syntax().text().replace(&format!("\n{:1$}", "", self.0 as usize * 4), "\n"), |
386 | make::tokens::whitespace( | 420 | ); |
387 | &ws.syntax() | 421 | rewriter.replace(ws.syntax(), &new_ws) |
388 | .text() | 422 | }); |
389 | .replace(&format!("\n{:1$}", "", self.0 as usize * 4), "\n"), | 423 | rewriter.rewrite(&node) |
390 | ) | ||
391 | .into(), | ||
392 | ) | ||
393 | }) | ||
394 | .collect(); | ||
395 | algo::replace_descendants(&node, |n| replacements.get(n).cloned()) | ||
396 | } | 424 | } |
397 | } | 425 | } |
398 | 426 | ||
@@ -442,12 +470,11 @@ pub trait AstNodeEdit: AstNode + Sized { | |||
442 | &self, | 470 | &self, |
443 | replacement_map: impl IntoIterator<Item = (D, D)>, | 471 | replacement_map: impl IntoIterator<Item = (D, D)>, |
444 | ) -> Self { | 472 | ) -> Self { |
445 | let map = replacement_map | 473 | let mut rewriter = SyntaxRewriter::default(); |
446 | .into_iter() | 474 | for (from, to) in replacement_map { |
447 | .map(|(from, to)| (from.syntax().clone().into(), to.syntax().clone().into())) | 475 | rewriter.replace(from.syntax(), to.syntax()) |
448 | .collect::<FxHashMap<SyntaxElement, _>>(); | 476 | } |
449 | let new_syntax = algo::replace_descendants(self.syntax(), |n| map.get(n).cloned()); | 477 | rewriter.rewrite_ast(self) |
450 | Self::cast(new_syntax).unwrap() | ||
451 | } | 478 | } |
452 | } | 479 | } |
453 | 480 | ||
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs index c3ae8f90e..392731dac 100644 --- a/crates/ra_syntax/src/ast/extensions.rs +++ b/crates/ra_syntax/src/ast/extensions.rs | |||
@@ -4,7 +4,7 @@ | |||
4 | use itertools::Itertools; | 4 | use itertools::Itertools; |
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
7 | ast::{self, child_opt, children, AstNode, AttrInput, SyntaxNode}, | 7 | ast::{self, child_opt, children, AstNode, AttrInput, NameOwner, SyntaxNode}, |
8 | SmolStr, SyntaxElement, | 8 | SmolStr, SyntaxElement, |
9 | SyntaxKind::*, | 9 | SyntaxKind::*, |
10 | SyntaxToken, T, | 10 | SyntaxToken, T, |
@@ -514,3 +514,14 @@ impl ast::Visibility { | |||
514 | self.syntax().children_with_tokens().any(|it| it.kind() == T![super]) | 514 | self.syntax().children_with_tokens().any(|it| it.kind() == T![super]) |
515 | } | 515 | } |
516 | } | 516 | } |
517 | |||
518 | impl ast::MacroCall { | ||
519 | pub fn is_macro_rules(&self) -> Option<ast::Name> { | ||
520 | let name_ref = self.path()?.segment()?.name_ref()?; | ||
521 | if name_ref.text() == "macro_rules" { | ||
522 | self.name() | ||
523 | } else { | ||
524 | None | ||
525 | } | ||
526 | } | ||
527 | } | ||
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs index 9f6f1cc53..1145b69e8 100644 --- a/crates/ra_syntax/src/ast/make.rs +++ b/crates/ra_syntax/src/ast/make.rs | |||
@@ -87,6 +87,9 @@ pub fn block_from_expr(e: ast::Expr) -> ast::Block { | |||
87 | pub fn expr_unit() -> ast::Expr { | 87 | pub fn expr_unit() -> ast::Expr { |
88 | expr_from_text("()") | 88 | expr_from_text("()") |
89 | } | 89 | } |
90 | pub fn expr_empty_block() -> ast::Expr { | ||
91 | expr_from_text("{}") | ||
92 | } | ||
90 | pub fn expr_unimplemented() -> ast::Expr { | 93 | pub fn expr_unimplemented() -> ast::Expr { |
91 | expr_from_text("unimplemented!()") | 94 | expr_from_text("unimplemented!()") |
92 | } | 95 | } |
@@ -136,6 +139,20 @@ pub fn placeholder_pat() -> ast::PlaceholderPat { | |||
136 | } | 139 | } |
137 | } | 140 | } |
138 | 141 | ||
142 | /// Creates a tuple of patterns from an interator of patterns. | ||
143 | /// | ||
144 | /// Invariant: `pats` must be length > 1 | ||
145 | /// | ||
146 | /// FIXME handle `pats` length == 1 | ||
147 | pub fn tuple_pat(pats: impl IntoIterator<Item = ast::Pat>) -> ast::TuplePat { | ||
148 | let pats_str = pats.into_iter().map(|p| p.to_string()).join(", "); | ||
149 | return from_text(&format!("({})", pats_str)); | ||
150 | |||
151 | fn from_text(text: &str) -> ast::TuplePat { | ||
152 | ast_from_text(&format!("fn f({}: ())", text)) | ||
153 | } | ||
154 | } | ||
155 | |||
139 | pub fn tuple_struct_pat( | 156 | pub fn tuple_struct_pat( |
140 | path: ast::Path, | 157 | path: ast::Path, |
141 | pats: impl IntoIterator<Item = ast::Pat>, | 158 | pats: impl IntoIterator<Item = ast::Pat>, |