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