1- use  std:: ops:: RangeInclusive ; 
1+ use  std:: { iter :: once ,   ops:: RangeInclusive } ; 
22
33use  hir:: { HasSource ,  ModuleSource } ; 
44use  ide_db:: { 
@@ -63,19 +63,6 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
6363        syntax:: NodeOrToken :: Token ( t)  => t. parent ( ) ?, 
6464    } ; 
6565
66-     //If the selection is inside impl block, we need to place new module outside impl block, 
67-     //as impl blocks cannot contain modules 
68- 
69-     let  mut  impl_parent:  Option < ast:: Impl >  = None ; 
70-     let  mut  impl_child_count:  usize  = 0 ; 
71-     if  let  Some ( parent_assoc_list)  = node. parent ( ) 
72-         && let  Some ( parent_impl)  = parent_assoc_list. parent ( ) 
73-         && let  Some ( impl_)  = ast:: Impl :: cast ( parent_impl) 
74-     { 
75-         impl_child_count = parent_assoc_list. children ( ) . count ( ) ; 
76-         impl_parent = Some ( impl_) ; 
77-     } 
78- 
7966    let  mut  curr_parent_module:  Option < ast:: Module >  = None ; 
8067    if  let  Some ( mod_syn_opt)  = node. ancestors ( ) . find ( |it| ast:: Module :: can_cast ( it. kind ( ) ) )  { 
8168        curr_parent_module = ast:: Module :: cast ( mod_syn_opt) ; 
@@ -94,7 +81,22 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
9481        return  None ; 
9582    } 
9683
97-     let  old_item_indent = module. body_items [ 0 ] . indent_level ( ) ; 
84+     let  mut  old_item_indent = module. body_items [ 0 ] . indent_level ( ) ; 
85+     let  old_items:  Vec < _ >  = module. use_items . iter ( ) . chain ( & module. body_items ) . cloned ( ) . collect ( ) ; 
86+ 
87+     // If the selection is inside impl block, we need to place new module outside impl block, 
88+     // as impl blocks cannot contain modules 
89+ 
90+     let  mut  impl_parent:  Option < ast:: Impl >  = None ; 
91+     let  mut  impl_child_count:  usize  = 0 ; 
92+     if  let  Some ( parent_assoc_list)  = module. body_items [ 0 ] . syntax ( ) . parent ( ) 
93+         && let  Some ( parent_impl)  = parent_assoc_list. parent ( ) 
94+         && let  Some ( impl_)  = ast:: Impl :: cast ( parent_impl) 
95+     { 
96+         impl_child_count = parent_assoc_list. children ( ) . count ( ) ; 
97+         old_item_indent = impl_. indent_level ( ) ; 
98+         impl_parent = Some ( impl_) ; 
99+     } 
98100
99101    acc. add ( 
100102        AssistId :: refactor_extract ( "extract_module" ) , 
@@ -127,7 +129,7 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
127129            let  import_items = module. resolve_imports ( curr_parent_module,  ctx) ; 
128130            module. change_visibility ( record_fields) ; 
129131
130-             let  module_def = generate_module_def ( & impl_parent,  module,  old_item_indent ) . to_string ( ) ; 
132+             let  module_def = generate_module_def ( & impl_parent,  & module) . indent ( old_item_indent ) ; 
131133
132134            let  mut  usages_to_be_processed_for_cur_file = vec ! [ ] ; 
133135            for  ( file_id,  usages)  in  usages_to_be_processed { 
@@ -149,62 +151,68 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
149151            if  let  Some ( impl_)  = impl_parent { 
150152                // Remove complete impl block if it has only one child (as such it will be empty 
151153                // after deleting that child) 
152-                 let  node_to_be_removed  = if  impl_child_count == 1  { 
153-                     impl_. syntax ( ) 
154+                 let  nodes_to_be_removed  = if  impl_child_count == old_items . len ( )  { 
155+                     vec ! [ impl_. syntax( ) ] 
154156                }  else  { 
155157                    //Remove selected node 
156-                     & node 
158+                     old_items . iter ( ) . map ( |it| it . syntax ( ) ) . collect ( ) 
157159                } ; 
158160
159-                 builder. delete ( node_to_be_removed. text_range ( ) ) ; 
160-                 // Remove preceding indentation from node 
161-                 if  let  Some ( range)  = indent_range_before_given_node ( node_to_be_removed)  { 
162-                     builder. delete ( range) ; 
161+                 for  node_to_be_removed in  nodes_to_be_removed { 
162+                     builder. delete ( node_to_be_removed. text_range ( ) ) ; 
163+                     // Remove preceding indentation from node 
164+                     if  let  Some ( range)  = indent_range_before_given_node ( node_to_be_removed)  { 
165+                         builder. delete ( range) ; 
166+                     } 
163167                } 
164168
165-                 builder. insert ( impl_. syntax ( ) . text_range ( ) . end ( ) ,  format ! ( "\n \n {module_def}" ) ) ; 
169+                 builder. insert ( 
170+                     impl_. syntax ( ) . text_range ( ) . end ( ) , 
171+                     format ! ( "\n \n {old_item_indent}{module_def}" ) , 
172+                 ) ; 
166173            }  else  { 
167174                for  import_item in  import_items { 
168175                    if  !module_text_range. contains_range ( import_item)  { 
169176                        builder. delete ( import_item) ; 
170177                    } 
171178                } 
172-                 builder. replace ( module_text_range,  module_def) 
179+                 builder. replace ( module_text_range,  module_def. to_string ( ) ) 
173180            } 
174181        } , 
175182    ) 
176183} 
177184
178185fn  generate_module_def ( 
179186    parent_impl :  & Option < ast:: Impl > , 
180-     module :  Module , 
181-     old_indent :  IndentLevel , 
187+     Module  {  name,  body_items,  use_items } :  & Module , 
182188)  -> ast:: Module  { 
183-     let  Module  {  name,  body_items,  use_items }  = module; 
184-     let  items = if  let  Some ( self_ty)  = parent_impl. as_ref ( ) . and_then ( |imp| imp. self_ty ( ) )  { 
189+     let  items:  Vec < _ >  = if  let  Some ( impl_)  = parent_impl. as_ref ( ) 
190+         && let  Some ( self_ty)  = impl_. self_ty ( ) 
191+     { 
185192        let  assoc_items = body_items
186-             . into_iter ( ) 
193+             . iter ( ) 
187194            . map ( |item| item. syntax ( ) . clone ( ) ) 
188195            . filter_map ( ast:: AssocItem :: cast) 
189196            . map ( |it| it. indent ( IndentLevel ( 1 ) ) ) 
190197            . collect_vec ( ) ; 
191-         let  assoc_item_list = make:: assoc_item_list ( Some ( assoc_items) ) ; 
192-         let  impl_ = make:: impl_ ( None ,  None ,  None ,  self_ty. clone ( ) ,  None ,  Some ( assoc_item_list) ) ; 
198+         let  assoc_item_list = make:: assoc_item_list ( Some ( assoc_items) ) . clone_for_update ( ) ; 
199+         let  impl_ = impl_. reset_indent ( ) ; 
200+         ted:: replace ( impl_. get_or_create_assoc_item_list ( ) . syntax ( ) ,  assoc_item_list. syntax ( ) ) ; 
193201        // Add the import for enum/struct corresponding to given impl block 
194202        let  use_impl = make_use_stmt_of_node_with_super ( self_ty. syntax ( ) ) ; 
195-         let   mut  module_body_items = use_items ; 
196-         module_body_items . insert ( 0 ,  use_impl ) ; 
197-         module_body_items . push ( ast:: Item :: Impl ( impl_) ) ; 
198-         module_body_items 
203+         once ( use_impl ) 
204+              . chain ( use_items . iter ( ) . cloned ( ) ) 
205+              . chain ( once ( ast:: Item :: Impl ( impl_) ) ) 
206+              . collect ( ) 
199207    }  else  { 
200-         [ use_items,   body_items] . concat ( ) 
208+         use_items. iter ( ) . chain ( body_items) . cloned ( ) . collect ( ) 
201209    } ; 
202210
203211    let  items = items. into_iter ( ) . map ( |it| it. reset_indent ( ) . indent ( IndentLevel ( 1 ) ) ) . collect_vec ( ) ; 
204212    let  module_body = make:: item_list ( Some ( items) ) ; 
205213
206214    let  module_name = make:: name ( name) ; 
207-     make:: mod_ ( module_name,  Some ( module_body) ) . indent ( old_indent ) 
215+     make:: mod_ ( module_name,  Some ( module_body) ) 
208216} 
209217
210218fn  make_use_stmt_of_node_with_super ( node_syntax :  & SyntaxNode )  -> ast:: Item  { 
@@ -1400,28 +1408,54 @@ mod modname {
14001408    fn  test_if_inside_impl_block_generate_module_outside ( )  { 
14011409        check_assist ( 
14021410            extract_module, 
1403-             r" 
1404-             struct A {} 
1411+             r"struct A {} 
14051412
14061413            impl A { 
1407- $0fn foo() {}$0 
1414+                  $0fn foo() {}$0
14081415                fn bar() {} 
14091416            } 
14101417        " , 
1411-             r" 
1412-             struct A {} 
1418+             r"struct A {} 
14131419
14141420            impl A { 
14151421                fn bar() {} 
14161422            } 
14171423
1418- mod modname { 
1419-     use super::A; 
1424+              mod modname {
1425+                  use super::A; 
14201426
1421-     impl A { 
1422-         pub(crate) fn foo() {} 
1423-     } 
1424- } 
1427+                 impl A { 
1428+                     pub(crate) fn foo() {} 
1429+                 } 
1430+             } 
1431+         " , 
1432+         ) ; 
1433+ 
1434+         check_assist ( 
1435+             extract_module, 
1436+             r"struct A {} 
1437+ 
1438+             impl A { 
1439+                 $0fn foo() {} 
1440+                 fn bar() {}$0 
1441+                 fn baz() {} 
1442+             } 
1443+         " , 
1444+             r"struct A {} 
1445+ 
1446+             impl A { 
1447+                 fn baz() {} 
1448+             } 
1449+ 
1450+             mod modname { 
1451+                 use super::A; 
1452+ 
1453+                 impl A { 
1454+                     pub(crate) fn foo() {} 
1455+ 
1456+                     pub(crate) fn bar() {} 
1457+                 } 
1458+             } 
14251459        " , 
14261460        ) 
14271461    } 
@@ -1430,27 +1464,25 @@ mod modname {
14301464    fn  test_if_inside_impl_block_generate_module_outside_but_impl_block_having_one_child ( )  { 
14311465        check_assist ( 
14321466            extract_module, 
1433-             r" 
1434-             struct A {} 
1467+             r"struct A {} 
14351468            struct B {} 
14361469
14371470            impl A { 
14381471$0fn foo(x: B) {}$0 
14391472            } 
14401473        " , 
1441-             r" 
1442-             struct A {} 
1474+             r"struct A {} 
14431475            struct B {} 
14441476
1445- mod modname { 
1446-     use super::A; 
1477+              mod modname {
1478+                  use super::A; 
14471479
1448-     use super::B; 
1480+                  use super::B; 
14491481
1450-     impl A { 
1451-         pub(crate) fn foo(x: B) {} 
1452-     } 
1453- } 
1482+                  impl A { 
1483+                      pub(crate) fn foo(x: B) {} 
1484+                  } 
1485+              }
14541486        " , 
14551487        ) 
14561488    } 
0 commit comments