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.rs68
1 files changed, 65 insertions, 3 deletions
diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs
index 23a0411ead..567bd09025 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,
};
@@ -194,6 +197,65 @@ 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>,
+ syntax_editor: &mut SyntaxEditor,
+ syntax_factory: &SyntaxFactory,
+ ) -> ast::IdentPat {
+ 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());
+ syntax_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
+ syntax_editor.replace(old_pat.syntax(), pat.syntax())
+ } else if let Some(at_token) = self.at_token() {
+ // Have an `@` token but not a pattern yet
+ syntax_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![
+ syntax_factory.whitespace(" ").into(),
+ syntax_factory.token(T![@]).into(),
+ syntax_factory.whitespace(" ").into(),
+ pat.syntax().clone().into(),
+ ];
+
+ if self.syntax().parent().is_none() {
+ let (mut 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 {
+ syntax_editor.insert_all(Position::after(name.syntax()), elements);
+ }
+ }
+ }
+ }
+ self.clone()
+ }
+}
+
#[test]
fn test_increase_indent() {
let arm_list = {