@@ -101,21 +101,22 @@ pub(crate) fn extract_struct_from_enum_variant(
101
101
} ) ;
102
102
}
103
103
104
- let indent = enum_ast. indent_level ( ) ;
105
104
let generic_params = enum_ast
106
105
. generic_param_list ( )
107
106
. and_then ( |known_generics| extract_generic_params ( & known_generics, & field_list) ) ;
108
107
let generics = generic_params. as_ref ( ) . map ( |generics| generics. clone_for_update ( ) ) ;
109
108
let def =
110
109
create_struct_def ( variant_name. clone ( ) , & variant, & field_list, generics, & enum_ast) ;
110
+
111
+ let enum_ast = variant. parent_enum ( ) ;
112
+ let indent = enum_ast. indent_level ( ) ;
111
113
def. reindent_to ( indent) ;
112
114
113
- let start_offset = & variant. parent_enum ( ) . syntax ( ) . clone ( ) ;
114
- ted:: insert_all_raw (
115
- ted:: Position :: before ( start_offset) ,
115
+ ted:: insert_all (
116
+ ted:: Position :: before ( enum_ast. syntax ( ) ) ,
116
117
vec ! [
117
118
def. syntax( ) . clone( ) . into( ) ,
118
- make:: tokens:: whitespace( & format!( "\n \n {}" , indent ) ) . into( ) ,
119
+ make:: tokens:: whitespace( & format!( "\n \n {indent}" ) ) . into( ) ,
119
120
] ,
120
121
) ;
121
122
@@ -227,7 +228,7 @@ fn tag_generics_in_variant(ty: &ast::Type, generics: &mut [(ast::GenericParam, b
227
228
}
228
229
229
230
fn create_struct_def (
230
- variant_name : ast:: Name ,
231
+ name : ast:: Name ,
231
232
variant : & ast:: Variant ,
232
233
field_list : & Either < ast:: RecordFieldList , ast:: TupleFieldList > ,
233
234
generics : Option < ast:: GenericParamList > ,
@@ -269,43 +270,27 @@ fn create_struct_def(
269
270
field_list. into ( )
270
271
}
271
272
} ;
272
-
273
273
field_list. reindent_to ( IndentLevel :: single ( ) ) ;
274
274
275
- let strukt = make:: struct_ ( enum_vis, variant_name, generics, field_list) . clone_for_update ( ) ;
276
-
277
- // FIXME: Consider making this an actual function somewhere (like in `AttrsOwnerEdit`) after some deliberation
278
- let attrs_and_docs = |node : & SyntaxNode | {
279
- let mut select_next_ws = false ;
280
- node. children_with_tokens ( ) . filter ( move |child| {
281
- let accept = match child. kind ( ) {
282
- ATTR | COMMENT => {
283
- select_next_ws = true ;
284
- return true ;
285
- }
286
- WHITESPACE if select_next_ws => true ,
287
- _ => false ,
288
- } ;
289
- select_next_ws = false ;
290
-
291
- accept
292
- } )
293
- } ;
275
+ let strukt = make:: struct_ ( enum_vis, name, generics, field_list) . clone_for_update ( ) ;
294
276
295
- // copy attributes & comments from variant
296
- let variant_attrs = attrs_and_docs ( variant. syntax ( ) )
297
- . map ( |tok| match tok. kind ( ) {
298
- WHITESPACE => make:: tokens:: single_newline ( ) . into ( ) ,
299
- _ => tok,
300
- } )
301
- . collect ( ) ;
302
- ted:: insert_all ( ted:: Position :: first_child_of ( strukt. syntax ( ) ) , variant_attrs) ;
277
+ // take comments from variant
278
+ ted:: insert_all (
279
+ ted:: Position :: first_child_of ( strukt. syntax ( ) ) ,
280
+ take_all_comments ( variant. syntax ( ) ) ,
281
+ ) ;
303
282
304
283
// copy attributes from enum
305
284
ted:: insert_all (
306
285
ted:: Position :: first_child_of ( strukt. syntax ( ) ) ,
307
- enum_. attrs ( ) . map ( |it| it. syntax ( ) . clone_for_update ( ) . into ( ) ) . collect ( ) ,
286
+ enum_
287
+ . attrs ( )
288
+ . flat_map ( |it| {
289
+ vec ! [ it. syntax( ) . clone_for_update( ) . into( ) , make:: tokens:: single_newline( ) . into( ) ]
290
+ } )
291
+ . collect ( ) ,
308
292
) ;
293
+
309
294
strukt
310
295
}
311
296
@@ -346,16 +331,48 @@ fn update_variant(variant: &ast::Variant, generics: Option<ast::GenericParamList
346
331
} )
347
332
. unwrap_or_else ( || make:: ty ( & name. text ( ) ) ) ;
348
333
334
+ // change from a record to a tuple field list
349
335
let tuple_field = make:: tuple_field ( None , ty) ;
350
- let replacement = make:: variant (
351
- name,
352
- Some ( ast:: FieldList :: TupleFieldList ( make:: tuple_field_list ( iter:: once ( tuple_field) ) ) ) ,
353
- )
354
- . clone_for_update ( ) ;
355
- ted:: replace ( variant. syntax ( ) , replacement. syntax ( ) ) ;
336
+ let field_list = make:: tuple_field_list ( iter:: once ( tuple_field) ) . clone_for_update ( ) ;
337
+ ted:: replace ( variant. field_list ( ) ?. syntax ( ) , field_list. syntax ( ) ) ;
338
+
339
+ // remove any ws after the name
340
+ if let Some ( ws) = name
341
+ . syntax ( )
342
+ . siblings_with_tokens ( syntax:: Direction :: Next )
343
+ . find_map ( |tok| tok. into_token ( ) . filter ( |tok| tok. kind ( ) == WHITESPACE ) )
344
+ {
345
+ ted:: remove ( SyntaxElement :: Token ( ws) ) ;
346
+ }
347
+
356
348
Some ( ( ) )
357
349
}
358
350
351
+ // Note: this also detaches whitespace after comments,
352
+ // since `SyntaxNode::splice_children` (and by extension `ted::insert_all_raw`)
353
+ // detaches nodes. If we only took the comments, we'd leave behind the old whitespace.
354
+ fn take_all_comments ( node : & SyntaxNode ) -> Vec < SyntaxElement > {
355
+ let mut remove_next_ws = false ;
356
+ node. children_with_tokens ( )
357
+ . filter_map ( move |child| match child. kind ( ) {
358
+ COMMENT => {
359
+ remove_next_ws = true ;
360
+ child. detach ( ) ;
361
+ Some ( child)
362
+ }
363
+ WHITESPACE if remove_next_ws => {
364
+ remove_next_ws = false ;
365
+ child. detach ( ) ;
366
+ Some ( make:: tokens:: single_newline ( ) . into ( ) )
367
+ }
368
+ _ => {
369
+ remove_next_ws = false ;
370
+ None
371
+ }
372
+ } )
373
+ . collect ( )
374
+ }
375
+
359
376
fn apply_references (
360
377
insert_use_cfg : InsertUseConfig ,
361
378
segment : ast:: PathSegment ,
@@ -480,10 +497,14 @@ enum En<T> { Var(Var<T>) }"#,
480
497
fn test_extract_struct_carries_over_attributes ( ) {
481
498
check_assist (
482
499
extract_struct_from_enum_variant,
483
- r#"#[derive(Debug)]
500
+ r#"
501
+ #[derive(Debug)]
484
502
#[derive(Clone)]
485
503
enum Enum { Variant{ field: u32$0 } }"# ,
486
- r#"#[derive(Debug)]#[derive(Clone)] struct Variant{ field: u32 }
504
+ r#"
505
+ #[derive(Debug)]
506
+ #[derive(Clone)]
507
+ struct Variant{ field: u32 }
487
508
488
509
#[derive(Debug)]
489
510
#[derive(Clone)]
@@ -614,7 +635,7 @@ enum A { One(One) }"#,
614
635
}
615
636
616
637
#[ test]
617
- fn test_extract_struct_keep_comments_and_attrs_on_variant_struct ( ) {
638
+ fn test_extract_struct_move_struct_variant_comments ( ) {
618
639
check_assist (
619
640
extract_struct_from_enum_variant,
620
641
r#"
@@ -631,19 +652,19 @@ enum A {
631
652
/* comment */
632
653
// other
633
654
/// comment
634
- #[attr]
635
655
struct One{
636
656
a: u32
637
657
}
638
658
639
659
enum A {
660
+ #[attr]
640
661
One(One)
641
662
}"# ,
642
663
) ;
643
664
}
644
665
645
666
#[ test]
646
- fn test_extract_struct_keep_comments_and_attrs_on_variant_tuple ( ) {
667
+ fn test_extract_struct_move_tuple_variant_comments ( ) {
647
668
check_assist (
648
669
extract_struct_from_enum_variant,
649
670
r#"
@@ -658,10 +679,10 @@ enum A {
658
679
/* comment */
659
680
// other
660
681
/// comment
661
- #[attr]
662
682
struct One(u32, u32);
663
683
664
684
enum A {
685
+ #[attr]
665
686
One(One)
666
687
}"# ,
667
688
) ;
0 commit comments