1
1
use ast:: edit:: IndentLevel ;
2
- use ide_db:: base_db:: { AnchoredPathBuf , SourceDatabaseExt } ;
2
+ use ide_db:: base_db:: AnchoredPathBuf ;
3
3
use syntax:: {
4
4
ast:: { self , edit:: AstNodeEdit , NameOwner } ,
5
5
AstNode ,
@@ -21,43 +21,44 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
21
21
// mod foo;
22
22
// ```
23
23
pub ( 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 ( ) ;
27
24
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 ( ) ;
30
25
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 ( ) ?;
31
31
let target = module_ast. syntax ( ) . text_range ( ) ;
32
32
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 ( ) ;
58
33
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
+ )
61
62
}
62
63
63
64
#[ cfg( test) ]
@@ -67,104 +68,66 @@ mod tests {
67
68
use super :: * ;
68
69
69
70
#[ test]
70
- fn extract_module_to_file_with_basic_module ( ) {
71
+ fn extract_from_root ( ) {
71
72
check_assist (
72
73
extract_module_to_file,
73
74
r#"
74
- //- /foo.rs crate:foo
75
75
mod tests {<|>
76
76
#[test] fn t() {}
77
77
}
78
78
"# ,
79
79
r#"
80
- //- /foo .rs
80
+ //- /main .rs
81
81
mod 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() {}
101
84
"# ,
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
+ ) ;
113
86
}
114
87
115
88
#[ test]
116
- fn extract_module_to_file_with_main_filw ( ) {
89
+ fn extract_from_submodule ( ) {
117
90
check_assist (
118
91
extract_module_to_file,
119
92
r#"
120
93
//- /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() {}
128
98
}
99
+ fn g() {}
129
100
"# ,
130
101
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
+ ) ;
141
109
}
142
110
143
111
#[ test]
144
- fn extract_module_to_file_with_lib_file ( ) {
112
+ fn extract_from_mod_rs ( ) {
145
113
check_assist (
146
114
extract_module_to_file,
147
115
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() {}
156
121
}
122
+ fn g() {}
157
123
"# ,
158
124
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
+ ) ;
169
132
}
170
133
}
0 commit comments