diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-09-26 20:31:28 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2019-09-26 20:31:28 +0100 |
commit | 1002e470747fe5887a2915689e21d9be3a1ca5d8 (patch) | |
tree | 3fd5903b67b498a39660b2dafdc929f33d41900e /crates/ra_syntax/src/ast | |
parent | 53a30d9e69ee5149e4fdb1c6fe4081281e879d0e (diff) | |
parent | d847d53e36571c8f7925b72cedf66bb203976148 (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.rs | 52 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/make.rs | 48 |
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 | |||
5 | use arrayvec::ArrayVec; | ||
6 | use std::ops::RangeInclusive; | ||
7 | |||
8 | use crate::{ | ||
9 | algo, | ||
10 | ast::{self, make, AstNode}, | ||
11 | InsertPosition, SyntaxElement, | ||
12 | }; | ||
13 | |||
14 | impl 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] | ||
35 | fn 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] | ||
45 | fn 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 | |||
137 | pub 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 | } | ||