aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-09-26 20:08:44 +0100
committerAleksey Kladov <[email protected]>2019-09-26 20:22:08 +0100
commitd847d53e36571c8f7925b72cedf66bb203976148 (patch)
tree3fd5903b67b498a39660b2dafdc929f33d41900e /crates
parent1a4b42400544a652a053a34263967689d47f554b (diff)
Start simplifying editing API
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_assists/src/assists/add_missing_impl_members.rs8
-rw-r--r--crates/ra_assists/src/assists/auto_import.rs1
-rw-r--r--crates/ra_assists/src/ast_editor.rs72
-rw-r--r--crates/ra_assists/src/lib.rs1
-rw-r--r--crates/ra_ide_api/src/line_index.rs1
-rw-r--r--crates/ra_ide_api/src/runnables.rs1
-rw-r--r--crates/ra_lsp_server/src/markdown.rs1
-rw-r--r--crates/ra_parser/src/grammar.rs1
-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
12 files changed, 107 insertions, 82 deletions
diff --git a/crates/ra_assists/src/assists/add_missing_impl_members.rs b/crates/ra_assists/src/assists/add_missing_impl_members.rs
index 23da1e65f..682455bce 100644
--- a/crates/ra_assists/src/assists/add_missing_impl_members.rs
+++ b/crates/ra_assists/src/assists/add_missing_impl_members.rs
@@ -100,12 +100,11 @@ fn strip_docstring(item: ast::ImplItem) -> ast::ImplItem {
100} 100}
101 101
102fn add_body(fn_def: ast::FnDef) -> ast::FnDef { 102fn add_body(fn_def: ast::FnDef) -> ast::FnDef {
103 let mut ast_editor = AstEditor::new(fn_def.clone());
104 if fn_def.body().is_none() { 103 if fn_def.body().is_none() {
105 let body = make::block_from_expr(make::expr_unimplemented()); 104 fn_def.with_body(make::block_from_expr(make::expr_unimplemented()))
106 ast_editor.set_body(&body); 105 } else {
106 fn_def
107 } 107 }
108 ast_editor.ast().to_owned()
109} 108}
110 109
111/// Given an `ast::ImplBlock`, resolves the target trait (the one being 110/// Given an `ast::ImplBlock`, resolves the target trait (the one being
@@ -332,5 +331,4 @@ impl Foo for S {
332}", 331}",
333 ) 332 )
334 } 333 }
335
336} 334}
diff --git a/crates/ra_assists/src/assists/auto_import.rs b/crates/ra_assists/src/assists/auto_import.rs
index 5aae98546..a91c170b9 100644
--- a/crates/ra_assists/src/assists/auto_import.rs
+++ b/crates/ra_assists/src/assists/auto_import.rs
@@ -448,7 +448,6 @@ fn make_assist_add_in_tree_list(
448 fmt_segments_raw(target, &mut buf); 448 fmt_segments_raw(target, &mut buf);
449 edit.insert(offset, buf); 449 edit.insert(offset, buf);
450 } else { 450 } else {
451
452 } 451 }
453} 452}
454 453
diff --git a/crates/ra_assists/src/ast_editor.rs b/crates/ra_assists/src/ast_editor.rs
index 2a685f26e..72c8c478a 100644
--- a/crates/ra_assists/src/ast_editor.rs
+++ b/crates/ra_assists/src/ast_editor.rs
@@ -6,7 +6,7 @@ use rustc_hash::FxHashMap;
6use ra_fmt::leading_indent; 6use ra_fmt::leading_indent;
7use ra_syntax::{ 7use ra_syntax::{
8 algo, 8 algo,
9 ast::{self, TypeBoundsOwner}, 9 ast::{self, make::tokens, TypeBoundsOwner},
10 AstNode, Direction, InsertPosition, SyntaxElement, 10 AstNode, Direction, InsertPosition, SyntaxElement,
11 SyntaxKind::*, 11 SyntaxKind::*,
12 T, 12 T,
@@ -229,26 +229,6 @@ impl AstEditor<ast::ImplItem> {
229 } 229 }
230} 230}
231 231
232impl AstEditor<ast::FnDef> {
233 pub fn set_body(&mut self, body: &ast::Block) {
234 let mut to_insert: ArrayVec<[SyntaxElement; 2]> = ArrayVec::new();
235 let old_body_or_semi: SyntaxElement = if let Some(old_body) = self.ast().body() {
236 old_body.syntax().clone().into()
237 } else if let Some(semi) = self.ast().semicolon_token() {
238 to_insert.push(tokens::single_space().into());
239 semi.into()
240 } else {
241 to_insert.push(tokens::single_space().into());
242 to_insert.push(body.syntax().clone().into());
243 self.ast = self.insert_children(InsertPosition::Last, to_insert.into_iter());
244 return;
245 };
246 to_insert.push(body.syntax().clone().into());
247 let replace_range = RangeInclusive::new(old_body_or_semi.clone(), old_body_or_semi);
248 self.ast = self.replace_children(replace_range, to_insert.into_iter())
249 }
250}
251
252impl AstEditor<ast::TypeParam> { 232impl AstEditor<ast::TypeParam> {
253 pub fn remove_bounds(&mut self) -> &mut Self { 233 pub fn remove_bounds(&mut self) -> &mut Self {
254 let colon = match self.ast.colon_token() { 234 let colon = match self.ast.colon_token() {
@@ -263,53 +243,3 @@ impl AstEditor<ast::TypeParam> {
263 self 243 self
264 } 244 }
265} 245}
266
267mod tokens {
268 use once_cell::sync::Lazy;
269 use ra_syntax::{AstNode, Parse, SourceFile, SyntaxKind::*, SyntaxToken, T};
270
271 static SOURCE_FILE: Lazy<Parse<SourceFile>> = Lazy::new(|| SourceFile::parse(",\n; ;"));
272
273 pub(crate) fn comma() -> SyntaxToken {
274 SOURCE_FILE
275 .tree()
276 .syntax()
277 .descendants_with_tokens()
278 .filter_map(|it| it.into_token())
279 .find(|it| it.kind() == T![,])
280 .unwrap()
281 }
282
283 pub(crate) fn single_space() -> SyntaxToken {
284 SOURCE_FILE
285 .tree()
286 .syntax()
287 .descendants_with_tokens()
288 .filter_map(|it| it.into_token())
289 .find(|it| it.kind() == WHITESPACE && it.text().as_str() == " ")
290 .unwrap()
291 }
292
293 #[allow(unused)]
294 pub(crate) fn single_newline() -> SyntaxToken {
295 SOURCE_FILE
296 .tree()
297 .syntax()
298 .descendants_with_tokens()
299 .filter_map(|it| it.into_token())
300 .find(|it| it.kind() == WHITESPACE && it.text().as_str() == "\n")
301 .unwrap()
302 }
303
304 pub(crate) struct WsBuilder(SourceFile);
305
306 impl WsBuilder {
307 pub(crate) fn new(text: &str) -> WsBuilder {
308 WsBuilder(SourceFile::parse(text).ok().unwrap())
309 }
310 pub(crate) fn ws(&self) -> SyntaxToken {
311 self.0.syntax().first_child_or_token().unwrap().into_token().unwrap()
312 }
313 }
314
315}
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index 897af2b02..3ca3320f7 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -340,5 +340,4 @@ mod tests {
340 assert_eq!(assists.next().expect("expected assist").0.label, "introduce variable"); 340 assert_eq!(assists.next().expect("expected assist").0.label, "introduce variable");
341 assert_eq!(assists.next().expect("expected assist").0.label, "replace with match"); 341 assert_eq!(assists.next().expect("expected assist").0.label, "replace with match");
342 } 342 }
343
344} 343}
diff --git a/crates/ra_ide_api/src/line_index.rs b/crates/ra_ide_api/src/line_index.rs
index 71de8a928..5fedad696 100644
--- a/crates/ra_ide_api/src/line_index.rs
+++ b/crates/ra_ide_api/src/line_index.rs
@@ -278,5 +278,4 @@ const C: char = \"メ メ\";
278 278
279 assert_eq!(col_index.utf16_to_utf8_col(2, 15), TextUnit::from_usize(15)); 279 assert_eq!(col_index.utf16_to_utf8_col(2, 15), TextUnit::from_usize(15));
280 } 280 }
281
282} 281}
diff --git a/crates/ra_ide_api/src/runnables.rs b/crates/ra_ide_api/src/runnables.rs
index 095ca56c4..8cf58fe79 100644
--- a/crates/ra_ide_api/src/runnables.rs
+++ b/crates/ra_ide_api/src/runnables.rs
@@ -229,5 +229,4 @@ mod tests {
229 let runnables = analysis.runnables(pos.file_id).unwrap(); 229 let runnables = analysis.runnables(pos.file_id).unwrap();
230 assert!(runnables.is_empty()) 230 assert!(runnables.is_empty())
231 } 231 }
232
233} 232}
diff --git a/crates/ra_lsp_server/src/markdown.rs b/crates/ra_lsp_server/src/markdown.rs
index c1eb0236a..3659edf8e 100644
--- a/crates/ra_lsp_server/src/markdown.rs
+++ b/crates/ra_lsp_server/src/markdown.rs
@@ -70,5 +70,4 @@ let a = 1;
70 "```rust\nfn main(){}\n```\nSome comment.\n```rust\nlet a = 1;\n```" 70 "```rust\nfn main(){}\n```\nSome comment.\n```rust\nlet a = 1;\n```"
71 ); 71 );
72 } 72 }
73
74} 73}
diff --git a/crates/ra_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs
index e2355aff9..6e9e212b7 100644
--- a/crates/ra_parser/src/grammar.rs
+++ b/crates/ra_parser/src/grammar.rs
@@ -135,7 +135,6 @@ pub(crate) mod fragments {
135 135
136 m.complete(p, MACRO_STMTS); 136 m.complete(p, MACRO_STMTS);
137 } 137 }
138
139} 138}
140 139
141pub(crate) fn reparser( 140pub(crate) fn reparser(
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}