11use ast:: edit:: IndentLevel ;
2- use ide_db:: base_db:: { AnchoredPathBuf , SourceDatabaseExt } ;
2+ use ide_db:: base_db:: AnchoredPathBuf ;
33use syntax:: {
44 ast:: { self , edit:: AstNodeEdit , NameOwner } ,
55 AstNode ,
@@ -21,43 +21,44 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
2121// mod foo;
2222// ```
2323pub ( crate ) fn extract_module_to_file ( acc : & mut Assists , ctx : & AssistContext ) -> Option < ( ) > {
24- let assist_id = AssistId ( "extract_module_to_file" , AssistKind :: RefactorExtract ) ;
25- let assist_label = "Extract module to file" ;
26- let db = ctx. db ( ) ;
2724 let module_ast = ctx. find_node_at_offset :: < ast:: Module > ( ) ?;
28- let module_items = module_ast. item_list ( ) ?;
29- let dedent_module_items_text = module_items. dedent ( IndentLevel ( 1 ) ) . to_string ( ) ;
3025 let module_name = module_ast. name ( ) ?;
26+
27+ let module_def = ctx. sema . to_def ( & module_ast) ?;
28+ let parent_module = module_def. parent ( ctx. db ( ) ) ?;
29+
30+ let module_items = module_ast. item_list ( ) ?;
3131 let target = module_ast. syntax ( ) . text_range ( ) ;
3232 let anchor_file_id = ctx. frange . file_id ;
33- let sr = db. file_source_root ( anchor_file_id) ;
34- let sr = db. source_root ( sr) ;
35- let file_path = sr. path_for_file ( & anchor_file_id) ?;
36- let ( file_name, file_ext) = file_path. name_and_extension ( ) ?;
37- acc. add ( assist_id, assist_label, target, |builder| {
38- builder. replace ( target, format ! ( "mod {};" , module_name) ) ;
39- let path = if is_main_or_lib ( file_name) {
40- format ! ( "./{}.{}" , module_name, file_ext. unwrap( ) )
41- } else {
42- format ! ( "./{}/{}.{}" , file_name, module_name, file_ext. unwrap( ) )
43- } ;
44- let dst = AnchoredPathBuf { anchor : anchor_file_id, path } ;
45- let contents = update_module_items_string ( dedent_module_items_text) ;
46- builder. create_file ( dst, contents) ;
47- } )
48- }
49- fn is_main_or_lib ( file_name : & str ) -> bool {
50- file_name == "main" . to_string ( ) || file_name == "lib" . to_string ( )
51- }
52- fn update_module_items_string ( items_str : String ) -> String {
53- let mut items_string_lines: Vec < & str > = items_str. lines ( ) . collect ( ) ;
54- items_string_lines. pop ( ) ; // Delete last line
55- items_string_lines. reverse ( ) ;
56- items_string_lines. pop ( ) ; // Delete first line
57- items_string_lines. reverse ( ) ;
5833
59- let string = items_string_lines. join ( "\n " ) ;
60- format ! ( "{}" , string)
34+ acc. add (
35+ AssistId ( "extract_module_to_file" , AssistKind :: RefactorExtract ) ,
36+ "Extract module to file" ,
37+ target,
38+ |builder| {
39+ let path = {
40+ let dir = match parent_module. name ( ctx. db ( ) ) {
41+ Some ( name) if !parent_module. is_mod_rs ( ctx. db ( ) ) => format ! ( "{}/" , name) ,
42+ _ => String :: new ( ) ,
43+ } ;
44+ format ! ( "./{}{}.rs" , dir, module_name)
45+ } ;
46+ let contents = {
47+ let items = module_items. dedent ( IndentLevel ( 1 ) ) . to_string ( ) ;
48+ let mut items =
49+ items. trim_start_matches ( '{' ) . trim_end_matches ( '}' ) . trim ( ) . to_string ( ) ;
50+ if !items. is_empty ( ) {
51+ items. push ( '\n' ) ;
52+ }
53+ items
54+ } ;
55+
56+ builder. replace ( target, format ! ( "mod {};" , module_name) ) ;
57+
58+ let dst = AnchoredPathBuf { anchor : anchor_file_id, path } ;
59+ builder. create_file ( dst, contents) ;
60+ } ,
61+ )
6162}
6263
6364#[ cfg( test) ]
@@ -67,104 +68,66 @@ mod tests {
6768 use super :: * ;
6869
6970 #[ test]
70- fn extract_module_to_file_with_basic_module ( ) {
71+ fn extract_from_root ( ) {
7172 check_assist (
7273 extract_module_to_file,
7374 r#"
74- //- /foo.rs crate:foo
7575mod tests {<|>
7676 #[test] fn t() {}
7777}
7878"# ,
7979 r#"
80- //- /foo .rs
80+ //- /main .rs
8181mod tests;
82- //- /foo/tests.rs
83- #[test] fn t() {}"# ,
84- )
85- }
86-
87- #[ test]
88- fn extract_module_to_file_with_file_path ( ) {
89- check_assist (
90- extract_module_to_file,
91- r#"
92- //- /src/foo.rs crate:foo
93- mod bar {<|>
94- fn f() {
95-
96- }
97- }
98- fn main() {
99- println!("Hello, world!");
100- }
82+ //- /tests.rs
83+ #[test] fn t() {}
10184"# ,
102- r#"
103- //- /src/foo.rs
104- mod bar;
105- fn main() {
106- println!("Hello, world!");
107- }
108- //- /src/foo/bar.rs
109- fn f() {
110-
111- }"# ,
112- )
85+ ) ;
11386 }
11487
11588 #[ test]
116- fn extract_module_to_file_with_main_filw ( ) {
89+ fn extract_from_submodule ( ) {
11790 check_assist (
11891 extract_module_to_file,
11992 r#"
12093//- /main.rs
121- mod foo {<|>
122- fn f() {
123-
124- }
125- }
126- fn main() {
127- println!("Hello, world!");
94+ mod submodule;
95+ //- /submodule.rs
96+ mod inner<|> {
97+ fn f() {}
12898}
99+ fn g() {}
129100"# ,
130101 r#"
131- //- /main.rs
132- mod foo;
133- fn main() {
134- println!("Hello, world!");
135- }
136- //- /foo.rs
137- fn f() {
138-
139- }"# ,
140- )
102+ //- /submodule.rs
103+ mod inner;
104+ fn g() {}
105+ //- /submodule/inner.rs
106+ fn f() {}
107+ "# ,
108+ ) ;
141109 }
142110
143111 #[ test]
144- fn extract_module_to_file_with_lib_file ( ) {
112+ fn extract_from_mod_rs ( ) {
145113 check_assist (
146114 extract_module_to_file,
147115 r#"
148- //- /lib.rs
149- mod foo {<|>
150- fn f() {
151-
152- }
153- }
154- fn main() {
155- println!("Hello, world!");
116+ //- /main.rs
117+ mod submodule;
118+ //- /submodule/mod.rs
119+ mod inner<|> {
120+ fn f() {}
156121}
122+ fn g() {}
157123"# ,
158124 r#"
159- //- /lib.rs
160- mod foo;
161- fn main() {
162- println!("Hello, world!");
163- }
164- //- /foo.rs
165- fn f() {
166-
167- }"# ,
168- )
125+ //- /submodule/mod.rs
126+ mod inner;
127+ fn g() {}
128+ //- /submodule/inner.rs
129+ fn f() {}
130+ "# ,
131+ ) ;
169132 }
170133}
0 commit comments