diff options
Diffstat (limited to 'crates/ra_syntax')
-rw-r--r-- | crates/ra_syntax/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast.rs | 1 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/edit.rs | 52 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/make.rs | 48 |
4 files changed, 103 insertions, 0 deletions
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml index 724c38e17..9bc85404a 100644 --- a/crates/ra_syntax/Cargo.toml +++ b/crates/ra_syntax/Cargo.toml | |||
@@ -12,6 +12,8 @@ itertools = "0.8.0" | |||
12 | rowan = "0.6.1" | 12 | rowan = "0.6.1" |
13 | rustc_lexer = "0.1.0" | 13 | rustc_lexer = "0.1.0" |
14 | rustc-hash = "1.0.1" | 14 | rustc-hash = "1.0.1" |
15 | arrayvec = "0.4.10" | ||
16 | once_cell = "1.2.0" | ||
15 | 17 | ||
16 | # ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here | 18 | # ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here |
17 | # to reduce number of compilations | 19 | # to reduce number of compilations |
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index f464d6534..fdffd8cb1 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs | |||
@@ -5,6 +5,7 @@ mod traits; | |||
5 | mod tokens; | 5 | mod tokens; |
6 | mod extensions; | 6 | mod extensions; |
7 | mod expr_extensions; | 7 | mod expr_extensions; |
8 | mod edit; | ||
8 | pub mod make; | 9 | pub mod make; |
9 | 10 | ||
10 | use std::marker::PhantomData; | 11 | use std::marker::PhantomData; |
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 | } | ||