Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/syntax/src/ast/edit.rs')
-rw-r--r--crates/syntax/src/ast/edit.rs97
1 files changed, 54 insertions, 43 deletions
diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs
index b20aa90d06..2e3a4016ee 100644
--- a/crates/syntax/src/ast/edit.rs
+++ b/crates/syntax/src/ast/edit.rs
@@ -2,15 +2,18 @@
//! immutable, all function here return a fresh copy of the tree, instead of
//! doing an in-place modification.
use parser::T;
-use std::{fmt, iter, ops};
+use std::{
+ fmt,
+ iter::{self, once},
+ ops,
+};
use crate::{
AstToken, NodeOrToken, SyntaxElement,
- SyntaxKind::WHITESPACE,
+ SyntaxKind::{ATTR, COMMENT, WHITESPACE},
SyntaxNode, SyntaxToken,
ast::{self, AstNode, HasName, make},
syntax_editor::{Position, SyntaxEditor, SyntaxMappingBuilder},
- ted,
};
use super::syntax_factory::SyntaxFactory;
@@ -84,29 +87,6 @@ impl IndentLevel {
IndentLevel(0)
}
- /// XXX: this intentionally doesn't change the indent of the very first token.
- /// For example, in something like:
- /// ```
- /// fn foo() -> i32 {
- /// 92
- /// }
- /// ```
- /// if you indent the block, the `{` token would stay put.
- pub(super) fn increase_indent(self, node: &SyntaxNode) {
- let tokens = node.preorder_with_tokens().filter_map(|event| match event {
- rowan::WalkEvent::Leave(NodeOrToken::Token(it)) => Some(it),
- _ => None,
- });
- for token in tokens {
- if let Some(ws) = ast::Whitespace::cast(token)
- && ws.text().contains('\n')
- {
- let new_ws = make::tokens::whitespace(&format!("{}{self}", ws.syntax()));
- ted::replace(ws.syntax(), &new_ws);
- }
- }
- }
-
pub(super) fn clone_increase_indent(self, node: &SyntaxNode) -> SyntaxNode {
let (editor, node) = SyntaxEditor::new(node.clone());
let tokens = node
@@ -124,23 +104,6 @@ impl IndentLevel {
editor.finish().new_root().clone()
}
- pub(super) fn decrease_indent(self, node: &SyntaxNode) {
- let tokens = node.preorder_with_tokens().filter_map(|event| match event {
- rowan::WalkEvent::Leave(NodeOrToken::Token(it)) => Some(it),
- _ => None,
- });
- for token in tokens {
- if let Some(ws) = ast::Whitespace::cast(token)
- && ws.text().contains('\n')
- {
- let new_ws = make::tokens::whitespace(
- &ws.syntax().text().replace(&format!("\n{self}"), "\n"),
- );
- ted::replace(ws.syntax(), &new_ws);
- }
- }
- }
-
pub(super) fn clone_decrease_indent(self, node: &SyntaxNode) -> SyntaxNode {
let (editor, node) = SyntaxEditor::new(node.clone());
let tokens = node
@@ -197,6 +160,28 @@ pub trait AstNodeEdit: AstNode + Clone + Sized {
impl<N: AstNode + Clone> AstNodeEdit for N {}
+pub trait AttrsOwnerEdit: ast::HasAttrs {
+ fn remove_attrs_and_docs(&self, editor: &SyntaxEditor) {
+ let mut remove_next_ws = false;
+ for child in self.syntax().children_with_tokens() {
+ match child.kind() {
+ ATTR | COMMENT => {
+ remove_next_ws = true;
+ editor.delete(child);
+ continue;
+ }
+ WHITESPACE if remove_next_ws => {
+ editor.delete(child);
+ }
+ _ => (),
+ }
+ remove_next_ws = false;
+ }
+ }
+}
+
+impl<T: ast::HasAttrs> AttrsOwnerEdit for T {}
+
impl ast::IdentPat {
pub fn set_pat(&self, pat: Option<ast::Pat>, editor: &SyntaxEditor) -> ast::IdentPat {
let make = editor.make();
@@ -252,6 +237,32 @@ impl ast::IdentPat {
}
}
+impl ast::UseTree {
+ pub fn wrap_in_tree_list_with_editor(&self) -> Option<ast::UseTree> {
+ if self.use_tree_list().is_some()
+ && self.path().is_none()
+ && self.star_token().is_none()
+ && self.rename().is_none()
+ {
+ return None;
+ }
+
+ let (editor, use_tree) = SyntaxEditor::with_ast_node(self);
+ let make = editor.make();
+ let first_child = use_tree.syntax().first_child_or_token()?;
+ let last_child = use_tree.syntax().last_child_or_token()?;
+ let use_tree_list = make.use_tree_list(once(self.clone()));
+ editor.replace_all(first_child..=last_child, vec![use_tree_list.syntax().clone().into()]);
+
+ let edit = editor.finish();
+ ast::UseTree::cast(edit.new_root().clone())
+ }
+}
+
+pub fn indent(node: &SyntaxNode, level: IndentLevel) -> SyntaxNode {
+ level.clone_increase_indent(node)
+}
+
#[test]
fn test_increase_indent() {
let arm_list = {