@@ -101,21 +101,22 @@ pub(crate) fn extract_struct_from_enum_variant(
101101 } ) ;
102102 }
103103
104- let indent = enum_ast. indent_level ( ) ;
105104 let generic_params = enum_ast
106105 . generic_param_list ( )
107106 . and_then ( |known_generics| extract_generic_params ( & known_generics, & field_list) ) ;
108107 let generics = generic_params. as_ref ( ) . map ( |generics| generics. clone_for_update ( ) ) ;
109108 let def =
110109 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 ( ) ;
111113 def. reindent_to ( indent) ;
112114
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 ( ) ) ,
116117 vec ! [
117118 def. syntax( ) . clone( ) . into( ) ,
118- make:: tokens:: whitespace( & format!( "\n \n {}" , indent ) ) . into( ) ,
119+ make:: tokens:: whitespace( & format!( "\n \n {indent}" ) ) . into( ) ,
119120 ] ,
120121 ) ;
121122
@@ -227,7 +228,7 @@ fn tag_generics_in_variant(ty: &ast::Type, generics: &mut [(ast::GenericParam, b
227228}
228229
229230fn create_struct_def (
230- variant_name : ast:: Name ,
231+ name : ast:: Name ,
231232 variant : & ast:: Variant ,
232233 field_list : & Either < ast:: RecordFieldList , ast:: TupleFieldList > ,
233234 generics : Option < ast:: GenericParamList > ,
@@ -269,43 +270,27 @@ fn create_struct_def(
269270 field_list. into ( )
270271 }
271272 } ;
272-
273273 field_list. reindent_to ( IndentLevel :: single ( ) ) ;
274274
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 ( ) ;
294276
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+ ) ;
303282
304283 // copy attributes from enum
305284 ted:: insert_all (
306285 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 ( ) ,
308292 ) ;
293+
309294 strukt
310295}
311296
@@ -346,16 +331,48 @@ fn update_variant(variant: &ast::Variant, generics: Option<ast::GenericParamList
346331 } )
347332 . unwrap_or_else ( || make:: ty ( & name. text ( ) ) ) ;
348333
334+ // change from a record to a tuple field list
349335 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+
356348 Some ( ( ) )
357349}
358350
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+
359376fn apply_references (
360377 insert_use_cfg : InsertUseConfig ,
361378 segment : ast:: PathSegment ,
@@ -480,10 +497,14 @@ enum En<T> { Var(Var<T>) }"#,
480497 fn test_extract_struct_carries_over_attributes ( ) {
481498 check_assist (
482499 extract_struct_from_enum_variant,
483- r#"#[derive(Debug)]
500+ r#"
501+ #[derive(Debug)]
484502#[derive(Clone)]
485503enum 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 }
487508
488509#[derive(Debug)]
489510#[derive(Clone)]
@@ -614,7 +635,7 @@ enum A { One(One) }"#,
614635 }
615636
616637 #[ test]
617- fn test_extract_struct_keep_comments_and_attrs_on_variant_struct ( ) {
638+ fn test_extract_struct_move_struct_variant_comments ( ) {
618639 check_assist (
619640 extract_struct_from_enum_variant,
620641 r#"
@@ -631,19 +652,19 @@ enum A {
631652/* comment */
632653// other
633654/// comment
634- #[attr]
635655struct One{
636656 a: u32
637657}
638658
639659enum A {
660+ #[attr]
640661 One(One)
641662}"# ,
642663 ) ;
643664 }
644665
645666 #[ test]
646- fn test_extract_struct_keep_comments_and_attrs_on_variant_tuple ( ) {
667+ fn test_extract_struct_move_tuple_variant_comments ( ) {
647668 check_assist (
648669 extract_struct_from_enum_variant,
649670 r#"
@@ -658,10 +679,10 @@ enum A {
658679/* comment */
659680// other
660681/// comment
661- #[attr]
662682struct One(u32, u32);
663683
664684enum A {
685+ #[attr]
665686 One(One)
666687}"# ,
667688 ) ;
0 commit comments