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.rs | 68 |
1 files changed, 63 insertions, 5 deletions
diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs index 23a0411ead..b20aa90d06 100644 --- a/crates/syntax/src/ast/edit.rs +++ b/crates/syntax/src/ast/edit.rs @@ -1,12 +1,15 @@ //! This module contains functions for editing syntax trees. As the trees are //! 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 crate::{ - AstToken, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxToken, - ast::{self, AstNode, make}, - syntax_editor::{SyntaxEditor, SyntaxMappingBuilder}, + AstToken, NodeOrToken, SyntaxElement, + SyntaxKind::WHITESPACE, + SyntaxNode, SyntaxToken, + ast::{self, AstNode, HasName, make}, + syntax_editor::{Position, SyntaxEditor, SyntaxMappingBuilder}, ted, }; @@ -105,7 +108,7 @@ impl IndentLevel { } pub(super) fn clone_increase_indent(self, node: &SyntaxNode) -> SyntaxNode { - let (mut editor, node) = SyntaxEditor::new(node.clone()); + let (editor, node) = SyntaxEditor::new(node.clone()); let tokens = node .preorder_with_tokens() .filter_map(|event| match event { @@ -139,7 +142,7 @@ impl IndentLevel { } pub(super) fn clone_decrease_indent(self, node: &SyntaxNode) -> SyntaxNode { - let (mut editor, node) = SyntaxEditor::new(node.clone()); + let (editor, node) = SyntaxEditor::new(node.clone()); let tokens = node .preorder_with_tokens() .filter_map(|event| match event { @@ -194,6 +197,61 @@ pub trait AstNodeEdit: AstNode + Clone + Sized { impl<N: AstNode + Clone> AstNodeEdit for N {} +impl ast::IdentPat { + pub fn set_pat(&self, pat: Option<ast::Pat>, editor: &SyntaxEditor) -> ast::IdentPat { + let make = editor.make(); + match pat { + None => { + if let Some(at_token) = self.at_token() { + // Remove `@ Pat` + let start = at_token.clone().into(); + let end = self + .pat() + .map(|it| it.syntax().clone().into()) + .unwrap_or_else(|| at_token.into()); + editor.delete_all(start..=end); + + // Remove any trailing ws + if let Some(last) = + self.syntax().last_token().filter(|it| it.kind() == WHITESPACE) + { + last.detach(); + } + } + } + Some(pat) => { + if let Some(old_pat) = self.pat() { + // Replace existing pattern + editor.replace(old_pat.syntax(), pat.syntax()) + } else if let Some(at_token) = self.at_token() { + // Have an `@` token but not a pattern yet + editor.insert(Position::after(at_token), pat.syntax()); + } else { + // Don't have an `@`, should have a name + let name = self.name().unwrap(); + let elements = vec![ + make.whitespace(" ").into(), + make.token(T![@]).into(), + make.whitespace(" ").into(), + pat.syntax().clone().into(), + ]; + + if self.syntax().parent().is_none() { + let (local, local_self) = SyntaxEditor::with_ast_node(self); + let local_name = local_self.name().unwrap(); + local.insert_all(Position::after(local_name.syntax()), elements); + let edit = local.finish(); + return ast::IdentPat::cast(edit.new_root().clone()).unwrap(); + } else { + editor.insert_all(Position::after(name.syntax()), elements); + } + } + } + } + self.clone() + } +} + #[test] fn test_increase_indent() { let arm_list = { |