aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax')
-rw-r--r--crates/ra_syntax/Cargo.toml2
-rw-r--r--crates/ra_syntax/src/ast.rs1
-rw-r--r--crates/ra_syntax/src/ast/edit.rs52
-rw-r--r--crates/ra_syntax/src/ast/make.rs48
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"
12rowan = "0.6.1" 12rowan = "0.6.1"
13rustc_lexer = "0.1.0" 13rustc_lexer = "0.1.0"
14rustc-hash = "1.0.1" 14rustc-hash = "1.0.1"
15arrayvec = "0.4.10"
16once_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;
5mod tokens; 5mod tokens;
6mod extensions; 6mod extensions;
7mod expr_extensions; 7mod expr_extensions;
8mod edit;
8pub mod make; 9pub mod make;
9 10
10use std::marker::PhantomData; 11use 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
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}