Start simplifying editing API

This commit is contained in:
Aleksey Kladov 2019-09-26 22:08:44 +03:00
parent 1a4b424005
commit d847d53e36
13 changed files with 114 additions and 87 deletions

View file

@ -0,0 +1,52 @@
//! 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 arrayvec::ArrayVec;
use std::ops::RangeInclusive;
use crate::{
algo,
ast::{self, make, AstNode},
InsertPosition, SyntaxElement,
};
impl ast::FnDef {
#[must_use]
pub fn with_body(&self, body: ast::Block) -> ast::FnDef {
let mut to_insert: ArrayVec<[SyntaxElement; 2]> = ArrayVec::new();
let old_body_or_semi: SyntaxElement = if let Some(old_body) = self.body() {
old_body.syntax().clone().into()
} else if let Some(semi) = self.semicolon_token() {
to_insert.push(make::tokens::single_space().into());
semi.into()
} else {
to_insert.push(make::tokens::single_space().into());
to_insert.push(body.syntax().clone().into());
return insert_children(self, InsertPosition::Last, to_insert.into_iter());
};
to_insert.push(body.syntax().clone().into());
let replace_range = RangeInclusive::new(old_body_or_semi.clone(), old_body_or_semi);
replace_children(self, replace_range, to_insert.into_iter())
}
}
#[must_use]
fn insert_children<N: AstNode>(
parent: &N,
position: InsertPosition<SyntaxElement>,
mut to_insert: impl Iterator<Item = SyntaxElement>,
) -> N {
let new_syntax = algo::insert_children(parent.syntax(), position, &mut to_insert);
N::cast(new_syntax).unwrap()
}
#[must_use]
fn replace_children<N: AstNode>(
parent: &N,
to_replace: RangeInclusive<SyntaxElement>,
mut to_insert: impl Iterator<Item = SyntaxElement>,
) -> N {
let new_syntax = algo::replace_children(parent.syntax(), to_replace, &mut to_insert);
N::cast(new_syntax).unwrap()
}

View file

@ -133,3 +133,51 @@ fn ast_from_text<N: AstNode>(text: &str) -> N {
let res = parse.tree().syntax().descendants().find_map(N::cast).unwrap();
res
}
pub mod tokens {
use crate::{AstNode, Parse, SourceFile, SyntaxKind::*, SyntaxToken, T};
use once_cell::sync::Lazy;
static SOURCE_FILE: Lazy<Parse<SourceFile>> = Lazy::new(|| SourceFile::parse(",\n; ;"));
pub fn comma() -> SyntaxToken {
SOURCE_FILE
.tree()
.syntax()
.descendants_with_tokens()
.filter_map(|it| it.into_token())
.find(|it| it.kind() == T![,])
.unwrap()
}
pub fn single_space() -> SyntaxToken {
SOURCE_FILE
.tree()
.syntax()
.descendants_with_tokens()
.filter_map(|it| it.into_token())
.find(|it| it.kind() == WHITESPACE && it.text().as_str() == " ")
.unwrap()
}
pub fn single_newline() -> SyntaxToken {
SOURCE_FILE
.tree()
.syntax()
.descendants_with_tokens()
.filter_map(|it| it.into_token())
.find(|it| it.kind() == WHITESPACE && it.text().as_str() == "\n")
.unwrap()
}
pub struct WsBuilder(SourceFile);
impl WsBuilder {
pub fn new(text: &str) -> WsBuilder {
WsBuilder(SourceFile::parse(text).ok().unwrap())
}
pub fn ws(&self) -> SyntaxToken {
self.0.syntax().first_child_or_token().unwrap().into_token().unwrap()
}
}
}