diff options
Diffstat (limited to 'crates/ra_assists/src/ast_editor.rs')
-rw-r--r-- | crates/ra_assists/src/ast_editor.rs | 116 |
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 @@ | |||
1 | use std::{iter, ops::RangeInclusive}; | 1 | use std::{iter, ops::RangeInclusive}; |
2 | 2 | ||
3 | use arrayvec::ArrayVec; | 3 | use arrayvec::ArrayVec; |
4 | use itertools::Itertools; | ||
5 | |||
4 | use hir::Name; | 6 | use hir::Name; |
5 | use ra_fmt::leading_indent; | 7 | use ra_fmt::leading_indent; |
6 | use ra_syntax::{ | 8 | use ra_syntax::{ |
@@ -17,7 +19,10 @@ pub struct AstEditor<N: AstNode> { | |||
17 | } | 19 | } |
18 | 20 | ||
19 | impl<N: AstNode> AstEditor<N> { | 21 | impl<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 | ||
91 | impl AstEditor<ast::NamedFieldList> { | 96 | impl 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 | ||
169 | impl AstEditor<ast::ItemList> { | 174 | impl 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 | ||
244 | impl AstBuilder<ast::NamedField> { | 248 | impl 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 | ||
295 | impl 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 | |||
305 | impl 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 | |||
315 | impl 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 | |||
325 | impl 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 | |||
339 | impl 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 | |||
350 | impl 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 | |||
361 | impl 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 | |||
372 | impl 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 | |||
291 | fn ast_node_from_file_text<N: AstNode>(text: &str) -> N { | 383 | fn 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 | ||