aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/ast
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-09-26 20:31:28 +0100
committerGitHub <[email protected]>2019-09-26 20:31:28 +0100
commit1002e470747fe5887a2915689e21d9be3a1ca5d8 (patch)
tree3fd5903b67b498a39660b2dafdc929f33d41900e /crates/ra_syntax/src/ast
parent53a30d9e69ee5149e4fdb1c6fe4081281e879d0e (diff)
parentd847d53e36571c8f7925b72cedf66bb203976148 (diff)
Merge #1921
1921: WIP: start simplifying editing API r=matklad a=matklad Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_syntax/src/ast')
-rw-r--r--crates/ra_syntax/src/ast/edit.rs52
-rw-r--r--crates/ra_syntax/src/ast/make.rs48
2 files changed, 100 insertions, 0 deletions
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs
new file mode 100644
index 000000000..c65899812
--- /dev/null
+++ b/crates/ra_syntax/src/ast/edit.rs
@@ -0,0 +1,52 @@
1//! This module contains functions for editing syntax trees. As the trees are
2//! immutable, all function here return a fresh copy of the tree, instead of
3//! doing an in-place modification.
4
5use arrayvec::ArrayVec;
6use std::ops::RangeInclusive;
7
8use crate::{
9 algo,
10 ast::{self, make, AstNode},
11 InsertPosition, SyntaxElement,
12};
13
14impl ast::FnDef {
15 #[must_use]
16 pub fn with_body(&self, body: ast::Block) -> ast::FnDef {
17 let mut to_insert: ArrayVec<[SyntaxElement; 2]> = ArrayVec::new();
18 let old_body_or_semi: SyntaxElement = if let Some(old_body) = self.body() {
19 old_body.syntax().clone().into()
20 } else if let Some(semi) = self.semicolon_token() {
21 to_insert.push(make::tokens::single_space().into());
22 semi.into()
23 } else {
24 to_insert.push(make::tokens::single_space().into());
25 to_insert.push(body.syntax().clone().into());
26 return insert_children(self, InsertPosition::Last, to_insert.into_iter());
27 };
28 to_insert.push(body.syntax().clone().into());
29 let replace_range = RangeInclusive::new(old_body_or_semi.clone(), old_body_or_semi);
30 replace_children(self, replace_range, to_insert.into_iter())
31 }
32}
33
34#[must_use]
35fn insert_children<N: AstNode>(
36 parent: &N,
37 position: InsertPosition<SyntaxElement>,
38 mut to_insert: impl Iterator<Item = SyntaxElement>,
39) -> N {
40 let new_syntax = algo::insert_children(parent.syntax(), position, &mut to_insert);
41 N::cast(new_syntax).unwrap()
42}
43
44#[must_use]
45fn replace_children<N: AstNode>(
46 parent: &N,
47 to_replace: RangeInclusive<SyntaxElement>,
48 mut to_insert: impl Iterator<Item = SyntaxElement>,
49) -> N {
50 let new_syntax = algo::replace_children(parent.syntax(), to_replace, &mut to_insert);
51 N::cast(new_syntax).unwrap()
52}
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs
index c06c62b3b..287a40bee 100644
--- a/crates/ra_syntax/src/ast/make.rs
+++ b/crates/ra_syntax/src/ast/make.rs
@@ -133,3 +133,51 @@ fn ast_from_text<N: AstNode>(text: &str) -> N {
133 let res = parse.tree().syntax().descendants().find_map(N::cast).unwrap(); 133 let res = parse.tree().syntax().descendants().find_map(N::cast).unwrap();
134 res 134 res
135} 135}
136
137pub mod tokens {
138 use crate::{AstNode, Parse, SourceFile, SyntaxKind::*, SyntaxToken, T};
139 use once_cell::sync::Lazy;
140
141 static SOURCE_FILE: Lazy<Parse<SourceFile>> = Lazy::new(|| SourceFile::parse(",\n; ;"));
142
143 pub fn comma() -> SyntaxToken {
144 SOURCE_FILE
145 .tree()
146 .syntax()
147 .descendants_with_tokens()
148 .filter_map(|it| it.into_token())
149 .find(|it| it.kind() == T![,])
150 .unwrap()
151 }
152
153 pub fn single_space() -> SyntaxToken {
154 SOURCE_FILE
155 .tree()
156 .syntax()
157 .descendants_with_tokens()
158 .filter_map(|it| it.into_token())
159 .find(|it| it.kind() == WHITESPACE && it.text().as_str() == " ")
160 .unwrap()
161 }
162
163 pub fn single_newline() -> SyntaxToken {
164 SOURCE_FILE
165 .tree()
166 .syntax()
167 .descendants_with_tokens()
168 .filter_map(|it| it.into_token())
169 .find(|it| it.kind() == WHITESPACE && it.text().as_str() == "\n")
170 .unwrap()
171 }
172
173 pub struct WsBuilder(SourceFile);
174
175 impl WsBuilder {
176 pub fn new(text: &str) -> WsBuilder {
177 WsBuilder(SourceFile::parse(text).ok().unwrap())
178 }
179 pub fn ws(&self) -> SyntaxToken {
180 self.0.syntax().first_child_or_token().unwrap().into_token().unwrap()
181 }
182 }
183}