aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/ast_editor.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src/ast_editor.rs')
-rw-r--r--crates/ra_assists/src/ast_editor.rs116
1 files changed, 104 insertions, 12 deletions
diff --git a/crates/ra_assists/src/ast_editor.rs b/crates/ra_assists/src/ast_editor.rs
index 95b871b30..6815638dc 100644
--- a/crates/ra_assists/src/ast_editor.rs
+++ b/crates/ra_assists/src/ast_editor.rs
@@ -1,6 +1,8 @@
1use std::{iter, ops::RangeInclusive}; 1use std::{iter, ops::RangeInclusive};
2 2
3use arrayvec::ArrayVec; 3use arrayvec::ArrayVec;
4use itertools::Itertools;
5
4use hir::Name; 6use hir::Name;
5use ra_fmt::leading_indent; 7use ra_fmt::leading_indent;
6use ra_syntax::{ 8use ra_syntax::{
@@ -17,7 +19,10 @@ pub struct AstEditor<N: AstNode> {
17} 19}
18 20
19impl<N: AstNode> AstEditor<N> { 21impl<N: AstNode> AstEditor<N> {
20 pub fn new(node: N) -> AstEditor<N> { 22 pub fn new(node: N) -> AstEditor<N>
23 where
24 N: Clone,
25 {
21 AstEditor { original_ast: node.clone(), ast: node } 26 AstEditor { original_ast: node.clone(), ast: node }
22 } 27 }
23 28
@@ -88,15 +93,15 @@ impl<N: AstNode> AstEditor<N> {
88 } 93 }
89} 94}
90 95
91impl AstEditor<ast::NamedFieldList> { 96impl AstEditor<ast::RecordFieldList> {
92 pub fn append_field(&mut self, field: &ast::NamedField) { 97 pub fn append_field(&mut self, field: &ast::RecordField) {
93 self.insert_field(InsertPosition::Last, field) 98 self.insert_field(InsertPosition::Last, field)
94 } 99 }
95 100
96 pub fn insert_field( 101 pub fn insert_field(
97 &mut self, 102 &mut self,
98 position: InsertPosition<&'_ ast::NamedField>, 103 position: InsertPosition<&'_ ast::RecordField>,
99 field: &ast::NamedField, 104 field: &ast::RecordField,
100 ) { 105 ) {
101 let is_multiline = self.ast().syntax().text().contains_char('\n'); 106 let is_multiline = self.ast().syntax().text().contains_char('\n');
102 let ws; 107 let ws;
@@ -168,8 +173,7 @@ impl AstEditor<ast::NamedFieldList> {
168 173
169impl AstEditor<ast::ItemList> { 174impl AstEditor<ast::ItemList> {
170 pub fn append_items(&mut self, items: impl Iterator<Item = ast::ImplItem>) { 175 pub fn append_items(&mut self, items: impl Iterator<Item = ast::ImplItem>) {
171 let n_existing_items = self.ast().impl_items().count(); 176 if !self.ast().syntax().text().contains_char('\n') {
172 if n_existing_items == 0 {
173 self.do_make_multiline(); 177 self.do_make_multiline();
174 } 178 }
175 items.for_each(|it| self.append_item(it)); 179 items.for_each(|it| self.append_item(it));
@@ -241,16 +245,16 @@ pub struct AstBuilder<N: AstNode> {
241 _phantom: std::marker::PhantomData<N>, 245 _phantom: std::marker::PhantomData<N>,
242} 246}
243 247
244impl AstBuilder<ast::NamedField> { 248impl AstBuilder<ast::RecordField> {
245 pub fn from_name(name: &Name) -> ast::NamedField { 249 pub fn from_name(name: &Name) -> ast::RecordField {
246 ast_node_from_file_text(&format!("fn f() {{ S {{ {}: (), }} }}", name)) 250 ast_node_from_file_text(&format!("fn f() {{ S {{ {}: (), }} }}", name))
247 } 251 }
248 252
249 fn from_text(text: &str) -> ast::NamedField { 253 fn from_text(text: &str) -> ast::RecordField {
250 ast_node_from_file_text(&format!("fn f() {{ S {{ {}, }} }}", text)) 254 ast_node_from_file_text(&format!("fn f() {{ S {{ {}, }} }}", text))
251 } 255 }
252 256
253 pub fn from_pieces(name: &ast::NameRef, expr: Option<&ast::Expr>) -> ast::NamedField { 257 pub fn from_pieces(name: &ast::NameRef, expr: Option<&ast::Expr>) -> ast::RecordField {
254 match expr { 258 match expr {
255 Some(expr) => Self::from_text(&format!("{}: {}", name.syntax(), expr.syntax())), 259 Some(expr) => Self::from_text(&format!("{}: {}", name.syntax(), expr.syntax())),
256 None => Self::from_text(&name.syntax().to_string()), 260 None => Self::from_text(&name.syntax().to_string()),
@@ -288,9 +292,97 @@ impl AstBuilder<ast::NameRef> {
288 } 292 }
289} 293}
290 294
295impl AstBuilder<ast::Path> {
296 fn from_text(text: &str) -> ast::Path {
297 ast_node_from_file_text(text)
298 }
299
300 pub fn from_pieces(enum_name: ast::Name, var_name: ast::Name) -> ast::Path {
301 Self::from_text(&format!("{}::{}", enum_name.syntax(), var_name.syntax()))
302 }
303}
304
305impl AstBuilder<ast::BindPat> {
306 fn from_text(text: &str) -> ast::BindPat {
307 ast_node_from_file_text(&format!("fn f({}: ())", text))
308 }
309
310 pub fn from_name(name: &ast::Name) -> ast::BindPat {
311 Self::from_text(name.text())
312 }
313}
314
315impl AstBuilder<ast::PlaceholderPat> {
316 fn from_text(text: &str) -> ast::PlaceholderPat {
317 ast_node_from_file_text(&format!("fn f({}: ())", text))
318 }
319
320 pub fn placeholder() -> ast::PlaceholderPat {
321 Self::from_text("_")
322 }
323}
324
325impl AstBuilder<ast::TupleStructPat> {
326 fn from_text(text: &str) -> ast::TupleStructPat {
327 ast_node_from_file_text(&format!("fn f({}: ())", text))
328 }
329
330 pub fn from_pieces(
331 path: &ast::Path,
332 pats: impl Iterator<Item = ast::Pat>,
333 ) -> ast::TupleStructPat {
334 let pats_str = pats.map(|p| p.syntax().to_string()).collect::<Vec<_>>().join(", ");
335 Self::from_text(&format!("{}({})", path.syntax(), pats_str))
336 }
337}
338
339impl AstBuilder<ast::RecordPat> {
340 fn from_text(text: &str) -> ast::RecordPat {
341 ast_node_from_file_text(&format!("fn f({}: ())", text))
342 }
343
344 pub fn from_pieces(path: &ast::Path, pats: impl Iterator<Item = ast::Pat>) -> ast::RecordPat {
345 let pats_str = pats.map(|p| p.syntax().to_string()).collect::<Vec<_>>().join(", ");
346 Self::from_text(&format!("{}{{ {} }}", path.syntax(), pats_str))
347 }
348}
349
350impl AstBuilder<ast::PathPat> {
351 fn from_text(text: &str) -> ast::PathPat {
352 ast_node_from_file_text(&format!("fn f({}: ())", text))
353 }
354
355 pub fn from_path(path: &ast::Path) -> ast::PathPat {
356 let path_str = path.syntax().text().to_string();
357 Self::from_text(path_str.as_str())
358 }
359}
360
361impl AstBuilder<ast::MatchArm> {
362 fn from_text(text: &str) -> ast::MatchArm {
363 ast_node_from_file_text(&format!("fn f() {{ match () {{{}}} }}", text))
364 }
365
366 pub fn from_pieces(pats: impl Iterator<Item = ast::Pat>, expr: &ast::Expr) -> ast::MatchArm {
367 let pats_str = pats.map(|p| p.syntax().to_string()).join(" | ");
368 Self::from_text(&format!("{} => {}", pats_str, expr.syntax()))
369 }
370}
371
372impl AstBuilder<ast::MatchArmList> {
373 fn from_text(text: &str) -> ast::MatchArmList {
374 ast_node_from_file_text(&format!("fn f() {{ match () {{{}}} }}", text))
375 }
376
377 pub fn from_arms(arms: impl Iterator<Item = ast::MatchArm>) -> ast::MatchArmList {
378 let arms_str = arms.map(|arm| format!("\n {}", arm.syntax())).join(",");
379 Self::from_text(&format!("{},\n", arms_str))
380 }
381}
382
291fn ast_node_from_file_text<N: AstNode>(text: &str) -> N { 383fn ast_node_from_file_text<N: AstNode>(text: &str) -> N {
292 let parse = SourceFile::parse(text); 384 let parse = SourceFile::parse(text);
293 let res = parse.tree().syntax().descendants().find_map(N::cast).unwrap().to_owned(); 385 let res = parse.tree().syntax().descendants().find_map(N::cast).unwrap();
294 res 386 res
295} 387}
296 388